diff --git a/mk/crates.mk b/mk/crates.mk index af2a663b61ded..aeb336f844fac 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -56,7 +56,7 @@ TARGET_CRATES := libc std flate arena term \ alloc_system RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \ rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \ - rustc_data_structures + rustc_data_structures rustc_platform_intrinsics HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros TOOLS := compiletest rustdoc rustc rustbook error-index-generator @@ -74,8 +74,8 @@ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_bo rustc_trans rustc_privacy rustc_lint DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \ - log syntax serialize rustc_llvm -DEPS_rustc_typeck := rustc syntax + log syntax serialize rustc_llvm rustc_platform_intrinsics +DEPS_rustc_typeck := rustc syntax rustc_platform_intrinsics DEPS_rustc_borrowck := rustc log graphviz syntax DEPS_rustc_resolve := rustc log syntax DEPS_rustc_privacy := rustc log syntax @@ -83,6 +83,7 @@ DEPS_rustc_lint := rustc log syntax DEPS_rustc := syntax flate arena serialize getopts rbml \ log graphviz rustc_llvm rustc_back rustc_data_structures DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags +DEPS_rustc_platform_intrinsics := rustc rustc_llvm DEPS_rustc_back := std syntax rustc_llvm flate log libc DEPS_rustc_data_structures := std log serialize DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \ diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index ae85e2712ce81..e226e9fa1549b 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -78,7 +78,8 @@ #![feature(optin_builtin_traits)] #![feature(reflect)] #![feature(rustc_attrs)] -#![feature(simd)] +#![cfg_attr(stage0, feature(simd))] +#![cfg_attr(not(stage0), feature(repr_simd, platform_intrinsics))] #![feature(staged_api)] #![feature(unboxed_closures)] @@ -150,7 +151,13 @@ pub mod iter; pub mod option; pub mod raw; pub mod result; + +#[cfg(stage0)] +#[path = "simd_old.rs"] +pub mod simd; +#[cfg(not(stage0))] pub mod simd; + pub mod slice; pub mod str; pub mod hash; diff --git a/src/libcore/simd.rs b/src/libcore/simd.rs index b06c0241093c3..fb39b3accc344 100644 --- a/src/libcore/simd.rs +++ b/src/libcore/simd.rs @@ -10,25 +10,12 @@ //! SIMD vectors. //! -//! These types can be used for accessing basic SIMD operations. Each of them -//! implements the standard arithmetic operator traits (Add, Sub, Mul, Div, -//! Rem, Shl, Shr) through compiler magic, rather than explicitly. Currently +//! These types can be used for accessing basic SIMD operations. Currently //! comparison operators are not implemented. To use SSE3+, you must enable //! the features, like `-C target-feature=sse3,sse4.1,sse4.2`, or a more //! specific `target-cpu`. No other SIMD intrinsics or high-level wrappers are //! provided beyond this module. //! -//! ```rust -//! #![feature(core_simd)] -//! -//! fn main() { -//! use std::simd::f32x4; -//! let a = f32x4(40.0, 41.0, 42.0, 43.0); -//! let b = f32x4(1.0, 1.1, 3.4, 9.8); -//! println!("{:?}", a + b); -//! } -//! ``` -//! //! # Stability Note //! //! These are all experimental. The interface may change entirely, without @@ -37,11 +24,38 @@ #![unstable(feature = "core_simd", reason = "needs an RFC to flesh out the design", issue = "27731")] +#![deprecated(since = "1.3.0", + reason = "use the external `simd` crate instead")] #![allow(non_camel_case_types)] #![allow(missing_docs)] +#![allow(deprecated)] + +use ops::{Add, Sub, Mul, Div, Shl, Shr, BitAnd, BitOr, BitXor}; + +// FIXME(stage0): the contents of macro can be inlined. +// ABIs are verified as valid as soon as they are parsed, i.e. before +// `cfg` stripping. The `platform-intrinsic` ABI is new, so stage0 +// doesn't know about it, but it still errors out when it hits it +// (despite this being in a `cfg(not(stage0))` module). +macro_rules! argh { + () => { + extern "platform-intrinsic" { + fn simd_add(x: T, y: T) -> T; + fn simd_sub(x: T, y: T) -> T; + fn simd_mul(x: T, y: T) -> T; + fn simd_div(x: T, y: T) -> T; + fn simd_shl(x: T, y: T) -> T; + fn simd_shr(x: T, y: T) -> T; + fn simd_and(x: T, y: T) -> T; + fn simd_or(x: T, y: T) -> T; + fn simd_xor(x: T, y: T) -> T; + } + } +} +argh!(); -#[simd] +#[repr(simd)] #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct i8x16(pub i8, pub i8, pub i8, pub i8, @@ -49,23 +63,23 @@ pub struct i8x16(pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8); -#[simd] +#[repr(simd)] #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct i16x8(pub i16, pub i16, pub i16, pub i16, pub i16, pub i16, pub i16, pub i16); -#[simd] +#[repr(simd)] #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct i32x4(pub i32, pub i32, pub i32, pub i32); -#[simd] +#[repr(simd)] #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct i64x2(pub i64, pub i64); -#[simd] +#[repr(simd)] #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct u8x16(pub u8, pub u8, pub u8, pub u8, @@ -73,28 +87,57 @@ pub struct u8x16(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8); -#[simd] +#[repr(simd)] #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct u16x8(pub u16, pub u16, pub u16, pub u16, pub u16, pub u16, pub u16, pub u16); -#[simd] +#[repr(simd)] #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct u32x4(pub u32, pub u32, pub u32, pub u32); -#[simd] +#[repr(simd)] #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct u64x2(pub u64, pub u64); -#[simd] +#[repr(simd)] #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct f32x4(pub f32, pub f32, pub f32, pub f32); -#[simd] +#[repr(simd)] #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct f64x2(pub f64, pub f64); + +macro_rules! impl_traits { + ($($trayt: ident, $method: ident, $func: ident: $($ty: ty),*;)*) => { + $($( + impl $trayt<$ty> for $ty { + type Output = Self; + fn $method(self, other: Self) -> Self { + unsafe { + $func(self, other) + } + } + } + )*)* + } +} + +impl_traits! { + Add, add, simd_add: u8x16, u16x8, u32x4, u64x2, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2; + Sub, sub, simd_sub: u8x16, u16x8, u32x4, u64x2, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2; + Mul, mul, simd_mul: u8x16, u16x8, u32x4, u64x2, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2; + + Div, div, simd_div: f32x4, f64x2; + + Shl, shl, simd_shl: u8x16, u16x8, u32x4, u64x2, i8x16, i16x8, i32x4, i64x2; + Shr, shr, simd_shr: u8x16, u16x8, u32x4, u64x2, i8x16, i16x8, i32x4, i64x2; + BitAnd, bitand, simd_and: u8x16, u16x8, u32x4, u64x2, i8x16, i16x8, i32x4, i64x2; + BitOr, bitor, simd_or: u8x16, u16x8, u32x4, u64x2, i8x16, i16x8, i32x4, i64x2; + BitXor, bitxor, simd_xor: u8x16, u16x8, u32x4, u64x2, i8x16, i16x8, i32x4, i64x2; +} diff --git a/src/libcore/simd_old.rs b/src/libcore/simd_old.rs new file mode 100644 index 0000000000000..7ecd08bea3574 --- /dev/null +++ b/src/libcore/simd_old.rs @@ -0,0 +1,98 @@ +// 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. +//! +//! These types can be used for accessing basic SIMD operations. Each of them +//! implements the standard arithmetic operator traits (Add, Sub, Mul, Div, +//! Rem, Shl, Shr) through compiler magic, rather than explicitly. Currently +//! comparison operators are not implemented. To use SSE3+, you must enable +//! the features, like `-C target-feature=sse3,sse4.1,sse4.2`, or a more +//! specific `target-cpu`. No other SIMD intrinsics or high-level wrappers are +//! provided beyond this module. +//! +//! ```rust +//! # #![feature(core_simd)] +//! fn main() { +//! use std::simd::f32x4; +//! let a = f32x4(40.0, 41.0, 42.0, 43.0); +//! let b = f32x4(1.0, 1.1, 3.4, 9.8); +//! println!("{:?}", a + b); +//! } +//! ``` +//! +//! # Stability Note +//! +//! These are all experimental. The interface may change entirely, without +//! warning. + +#![unstable(feature = "core_simd", + reason = "needs an RFC to flesh out the design")] + +#![allow(non_camel_case_types)] +#![allow(missing_docs)] + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct i8x16(pub i8, pub i8, pub i8, pub i8, + pub i8, pub i8, pub i8, pub i8, + pub i8, pub i8, pub i8, pub i8, + pub i8, pub i8, pub i8, pub i8); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct i16x8(pub i16, pub i16, pub i16, pub i16, + pub i16, pub i16, pub i16, pub i16); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct i32x4(pub i32, pub i32, pub i32, pub i32); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct i64x2(pub i64, pub i64); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct u8x16(pub u8, pub u8, pub u8, pub u8, + pub u8, pub u8, pub u8, pub u8, + pub u8, pub u8, pub u8, pub u8, + pub u8, pub u8, pub u8, pub u8); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct u16x8(pub u16, pub u16, pub u16, pub u16, + pub u16, pub u16, pub u16, pub u16); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct u64x2(pub u64, pub u64); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct f64x2(pub f64, pub f64); diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index c34b2ea58dcc8..3f182b4d2b5bb 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -704,7 +704,7 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> { } fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod) { - if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic { + if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic || fm.abi == abi::PlatformIntrinsic { return; } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 91638f0de7e3f..d9e6e8c12f1e3 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1501,7 +1501,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext, encode_family(rbml_w, FN_FAMILY); encode_bounds_and_type_for_item(rbml_w, ecx, nitem.id); encode_name(rbml_w, nitem.ident.name); - if abi == abi::RustIntrinsic { + if abi == abi::RustIntrinsic || abi == abi::PlatformIntrinsic { encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(nitem)); } encode_attributes(rbml_w, &*nitem.attrs); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 967eb3ff74f49..d7a58f4cdd08c 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3312,10 +3312,10 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> { variants: Vec>) -> Self { let mut flags = AdtFlags::NO_ADT_FLAGS; let attrs = tcx.get_attrs(did); - if attrs.iter().any(|item| item.check_name("fundamental")) { + if attr::contains_name(&attrs, "fundamental") { flags = flags | AdtFlags::IS_FUNDAMENTAL; } - if attrs.iter().any(|item| item.check_name("simd")) { + if tcx.lookup_simd(did) { flags = flags | AdtFlags::IS_SIMD; } if Some(did) == tcx.lang_items.phantom_data() { @@ -6116,6 +6116,7 @@ impl<'tcx> ctxt<'tcx> { /// Determine whether an item is annotated with `#[simd]` pub fn lookup_simd(&self, did: DefId) -> bool { self.has_attr(did, "simd") + || self.lookup_repr_hints(did).contains(&attr::ReprSimd) } /// Obtain the representation annotation for a struct definition. diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 263a8e1480702..346e7a7bf9886 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -406,8 +406,10 @@ pub fn phase_2_configure_and_expand(sess: &Session, // // baz! should not use this definition unless foo is enabled. - krate = time(time_passes, "configuration 1", move || - syntax::config::strip_unconfigured_items(sess.diagnostic(), krate)); + let mut feature_gated_cfgs = vec![]; + krate = time(time_passes, "configuration 1", || + syntax::config::strip_unconfigured_items(sess.diagnostic(), krate, + &mut feature_gated_cfgs)); *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs); @@ -511,6 +513,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, cfg, macros, syntax_exts, + &mut feature_gated_cfgs, krate); if cfg!(windows) { env::set_var("PATH", &_old_path); @@ -536,7 +539,17 @@ pub fn phase_2_configure_and_expand(sess: &Session, // strip again, in case expansion added anything with a #[cfg]. krate = time(time_passes, "configuration 2", || - syntax::config::strip_unconfigured_items(sess.diagnostic(), krate)); + syntax::config::strip_unconfigured_items(sess.diagnostic(), krate, + &mut feature_gated_cfgs)); + + time(time_passes, "gated configuration checking", || { + let features = sess.features.borrow(); + feature_gated_cfgs.sort(); + feature_gated_cfgs.dedup(); + for cfg in &feature_gated_cfgs { + cfg.check_and_emit(sess.diagnostic(), &features); + } + }); krate = time(time_passes, "maybe building test harness", || syntax::test::modify_for_testing(&sess.parse_sess, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 1d440af269713..60eaffd71cbc6 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -89,6 +89,7 @@ pub mod test; pub mod driver; pub mod pretty; +pub mod target_features; const BUG_REPORT_URL: &'static str = @@ -136,7 +137,8 @@ pub fn run_compiler<'a>(args: &[String], if sess.unstable_options() { sess.opts.show_span = matches.opt_str("show-span"); } - let cfg = config::build_configuration(&sess); + let mut cfg = config::build_configuration(&sess); + target_features::add_configuration(&mut cfg, &sess); do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile)); diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs new file mode 100644 index 0000000000000..ca76046acf0fb --- /dev/null +++ b/src/librustc_driver/target_features.rs @@ -0,0 +1,98 @@ +// 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. + +use syntax::{ast, attr}; +use rustc::session::Session; +use syntax::parse::token::InternedString; +use syntax::parse::token::intern_and_get_ident as intern; + +/// Add `target_feature = "..."` cfgs for a variety of platform +/// specific features (SSE, NEON etc.). +/// +/// This uses a scheme similar to that employed by clang: reimplement +/// the target feature knowledge. *Theoretically* we could query LLVM +/// since that has perfect knowledge about what things are enabled in +/// code-generation, however, it is extremely non-obvious how to do +/// this successfully. Each platform defines a subclass of a +/// SubtargetInfo, which knows all this information, but the ways to +/// query them do not seem to be public. +pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) { + let tf = InternedString::new("target_feature"); + macro_rules! fillout { + ($($func: ident, $name: expr;)*) => {{ + $(if $func(sess) { + cfg.push(attr::mk_name_value_item_str(tf.clone(), intern($name))) + })* + }} + } + fillout! { + has_sse, "sse"; + has_sse2, "sse2"; + has_sse3, "sse3"; + has_ssse3, "ssse3"; + has_sse41, "sse4.1"; + has_sse42, "sse4.2"; + has_avx, "avx"; + has_avx2, "avx2"; + has_neon, "neon"; + has_vfp, "vfp"; + } +} + + +fn features_contain(sess: &Session, s: &str) -> bool { + sess.target.target.options.features.contains(s) || + sess.opts.cg.target_feature.contains(s) +} + +pub fn has_sse(sess: &Session) -> bool { + features_contain(sess, "+sse") || + has_sse2(sess) +} +pub fn has_sse2(sess: &Session) -> bool { + // x86-64 requires at least SSE2 support + sess.target.target.arch == "x86_64" || + features_contain(sess, "+sse2") || + has_sse3(sess) +} +pub fn has_sse3(sess: &Session) -> bool { + features_contain(sess, "+sse3") || + has_ssse3(sess) +} +pub fn has_ssse3(sess: &Session) -> bool { + features_contain(sess, "+ssse3") || + has_sse41(sess) +} +pub fn has_sse41(sess: &Session) -> bool { + features_contain(sess, "+sse4.1") || + has_sse42(sess) +} +pub fn has_sse42(sess: &Session) -> bool { + features_contain(sess, "+sse4.2") || + has_avx(sess) +} +pub fn has_avx(sess: &Session) -> bool { + features_contain(sess, "+avx") || + has_avx2(sess) +} +pub fn has_avx2(sess: &Session) -> bool { + features_contain(sess, "+avx2") +} + +pub fn has_neon(sess: &Session) -> bool { + // AArch64 requires NEON support + sess.target.target.arch == "aarch64" || + features_contain(sess, "+neon") +} +pub fn has_vfp(sess: &Session) -> bool { + // AArch64 requires VFP support + sess.target.target.arch == "aarch64" || + features_contain(sess, "+vfp") +} diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f581931647765..523ab7b527a14 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -603,6 +603,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match bare_fn.abi { abi::Rust | abi::RustIntrinsic | + abi::PlatformIntrinsic | abi::RustCall => { return FfiUnsafe( "found function pointer with Rust calling \ @@ -717,7 +718,9 @@ impl LintPass for ImproperCTypes { } match it.node { - ast::ItemForeignMod(ref nmod) if nmod.abi != abi::RustIntrinsic => { + ast::ItemForeignMod(ref nmod) + if nmod.abi != abi::RustIntrinsic && + nmod.abi != abi::PlatformIntrinsic => { for ni in &nmod.items { match ni.node { ast::ForeignItemFn(ref decl, _) => check_foreign_fn(cx, &**decl), diff --git a/src/librustc_platform_intrinsics/aarch64.rs b/src/librustc_platform_intrinsics/aarch64.rs new file mode 100644 index 0000000000000..e7b11e45fd6c7 --- /dev/null +++ b/src/librustc_platform_intrinsics/aarch64.rs @@ -0,0 +1,51 @@ +// 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. + +use {Intrinsic, i, f, v}; +use rustc::middle::ty; + +macro_rules! p { + ($name: expr, ($($inputs: tt),*) -> $output: tt) => { + plain!(concat!("llvm.aarch64.neon.", $name), ($($inputs),*) -> $output) + } +} +pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { + Some(match name { + "vmaxvq_u8" => p!("umaxv.i8.v16i8", (i8x16) -> i8), + "vmaxvq_u16" => p!("umaxv.i16.v8i16", (i16x8) -> i16), + "vmaxvq_u32" => p!("umaxv.i32.v4i32", (i32x4) -> i32), + + "vmaxvq_s8" => p!("smaxv.i8.v16i8", (i8x16) -> i8), + "vmaxvq_s16" => p!("smaxv.i16.v8i16", (i16x8) -> i16), + "vmaxvq_s32" => p!("smaxv.i32.v4i32", (i32x4) -> i32), + + "vminvq_u8" => p!("uminv.i8.v16i8", (i8x16) -> i8), + "vminvq_u16" => p!("uminv.i16.v8i16", (i16x8) -> i16), + "vminvq_u32" => p!("uminv.i32.v4i32", (i32x4) -> i32), + "vminvq_s8" => p!("sminv.i8.v16i8", (i8x16) -> i8), + "vminvq_s16" => p!("sminv.i16.v8i16", (i16x8) -> i16), + "vminvq_s32" => p!("sminv.i32.v4i32", (i32x4) -> i32), + + "vsqrtq_f32" => plain!("llvm.sqrt.v4f32", (f32x4) -> f32x4), + "vsqrtq_f64" => plain!("llvm.sqrt.v2f64", (f64x2) -> f64x2), + + "vrsqrteq_f32" => p!("vrsqrte.v4f32", (f32x4) -> f32x4), + "vrsqrteq_f64" => p!("vrsqrte.v2f64", (f64x2) -> f64x2), + "vrecpeq_f32" => p!("vrecpe.v4f32", (f32x4) -> f32x4), + "vrecpeq_f64" => p!("vrecpe.v2f64", (f64x2) -> f64x2), + + "vmaxq_f32" => p!("fmax.v4f32", (f32x4, f32x4) -> f32x4), + "vmaxq_f64" => p!("fmax.v2f64", (f64x2, f64x2) -> f64x2), + + "vminq_f32" => p!("fmin.v4f32", (f32x4, f32x4) -> f32x4), + "vminq_f64" => p!("fmin.v2f64", (f64x2, f64x2) -> f64x2), + _ => return None, + }) +} diff --git a/src/librustc_platform_intrinsics/arm.rs b/src/librustc_platform_intrinsics/arm.rs new file mode 100644 index 0000000000000..f29f7e384b4fb --- /dev/null +++ b/src/librustc_platform_intrinsics/arm.rs @@ -0,0 +1,347 @@ +// 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. + +use {Intrinsic, i, f, v}; +use rustc::middle::ty; + +macro_rules! p { + ($name: expr, ($($inputs: tt),*) -> $output: tt) => { + plain!(concat!("llvm.arm.neon.", $name), ($($inputs),*) -> $output) + } +} +pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { + if !name.starts_with("v") { return None } + Some(match &name["v".len()..] { + "sqrtq_f32" => plain!("llvm.sqrt.v4f32", (f32x4) -> f32x4), + "sqrtq_f64" => plain!("llvm.sqrt.v2f64", (f64x2) -> f64x2), + + "hadd_s8" => p!("vhadds.v8i8", (i8x8, i8x8) -> i8x8), + "haddq_s8" => p!("vhadds.v16i8", (i8x16, i8x16) -> i8x16), + "hadd_s16" => p!("vhadds.v4i16", (i16x4, i16x4) -> i16x4), + "haddq_s16" => p!("vhadds.v8i16", (i16x8, i16x8) -> i16x8), + "hadd_s32" => p!("vhadds.v2i32", (i32x2, i32x2) -> i32x2), + "haddq_s32" => p!("vhadds.v4i32", (i32x4, i32x4) -> i32x4), + "hadd_u8" => p!("vhaddu.v8i8", (i8x8, i8x8) -> i8x8), + "haddq_u8" => p!("vhaddu.v16i8", (i8x16, i8x16) -> i8x16), + "hadd_u16" => p!("vhaddu.v4i16", (i16x4, i16x4) -> i16x4), + "haddq_u16" => p!("vhaddu.v8i16", (i16x8, i16x8) -> i16x8), + "hadd_u32" => p!("vhaddu.v2i32", (i32x2, i32x2) -> i32x2), + "haddq_u32" => p!("vhaddu.v4i32", (i32x4, i32x4) -> i32x4), + "rhadd_s8" => p!("vrhadds.v8i8", (i8x8, i8x8) -> i8x8), + "rhaddq_s8" => p!("vrhadds.v16i8", (i8x16, i8x16) -> i8x16), + "rhadd_s16" => p!("vrhadds.v4i16", (i16x4, i16x4) -> i16x4), + "rhaddq_s16" => p!("vrhadds.v8i16", (i16x8, i16x8) -> i16x8), + "rhadd_s32" => p!("vrhadds.v2i32", (i32x2, i32x2) -> i32x2), + "rhaddq_s32" => p!("vrhadds.v4i32", (i32x4, i32x4) -> i32x4), + "rhadd_u8" => p!("vrhaddu.v8i8", (i8x8, i8x8) -> i8x8), + "rhaddq_u8" => p!("vrhaddu.v16i8", (i8x16, i8x16) -> i8x16), + "rhadd_u16" => p!("vrhaddu.v4i16", (i16x4, i16x4) -> i16x4), + "rhaddq_u16" => p!("vrhaddu.v8i16", (i16x8, i16x8) -> i16x8), + "rhadd_u32" => p!("vrhaddu.v2i32", (i32x2, i32x2) -> i32x2), + "rhaddq_u32" => p!("vrhaddu.v4i32", (i32x4, i32x4) -> i32x4), + "qadd_s8" => p!("vqadds.v8i8", (i8x8, i8x8) -> i8x8), + "qaddq_s8" => p!("vqadds.v16i8", (i8x16, i8x16) -> i8x16), + "qadd_s16" => p!("vqadds.v4i16", (i16x4, i16x4) -> i16x4), + "qaddq_s16" => p!("vqadds.v8i16", (i16x8, i16x8) -> i16x8), + "qadd_s32" => p!("vqadds.v2i32", (i32x2, i32x2) -> i32x2), + "qaddq_s32" => p!("vqadds.v4i32", (i32x4, i32x4) -> i32x4), + "qadd_s64" => p!("vqaddu.v1i64", (i64x1, i64x1) -> i64x1), + "qaddq_s64" => p!("vqaddu.v2i64", (i64x2, i64x2) -> i64x2), + "qadd_u8" => p!("vqaddu.v8i8", (i8x8, i8x8) -> i8x8), + "qaddq_u8" => p!("vqaddu.v16i8", (i8x16, i8x16) -> i8x16), + "qadd_u16" => p!("vqaddu.v4i16", (i16x4, i16x4) -> i16x4), + "qaddq_u16" => p!("vqaddu.v8i16", (i16x8, i16x8) -> i16x8), + "qadd_u32" => p!("vqaddu.v2i32", (i32x2, i32x2) -> i32x2), + "qaddq_u32" => p!("vqaddu.v4i32", (i32x4, i32x4) -> i32x4), + "qadd_u64" => p!("vqaddu.v1i64", (i64x1, i64x1) -> i64x1), + "qaddq_u64" => p!("vqaddu.v2i64", (i64x2, i64x2) -> i64x2), + "raddhn_s16" => p!("vraddhn.v8i8", (i16x8, i16x8) -> i8x8), + "raddhn_s32" => p!("vraddhn.v4i16", (i32x4, i32x4) -> i16x4), + "raddhn_s64" => p!("vraddhn.v2i32", (i64x2, i64x2) -> i32x2), + "fma_f32" => plain!("llvm.fma.v2f32", (f32x2, f32x2, f32x2) -> f32x2), + "fmaq_f32" => plain!("llvm.fma.v4f32", (f32x4, f32x4, f32x4) -> f32x4), + "qdmulh_s16" => p!("vqdmulh.v4i16", (i16x4, i16x4) -> i16x4), + "qdmulhq_s16" => p!("vqdmulh.v8i16", (i16x8, i16x8) -> i16x8), + "qdmulh_s32" => p!("vqdmulh.v2i32", (i32x2, i32x2) -> i32x4), + "qdmulhq_s32" => p!("vqdmulh.v4i32", (i32x4, i32x4) -> i32x4), + "qrdmulh_s16" => p!("vqrdmulh.v4i16", (i16x4, i16x4) -> i16x4), + "qrdmulhqr_s16" => p!("vqrdmulh.v8i16", (i16x8, i16x8) -> i16x8), + "qrdmulh_s32" => p!("vqrdmulh.v2i32", (i32x2, i32x2) -> i32x4), + "qrdmulhqr_s32" => p!("vqrdmulh.v4i32", (i32x4, i32x4) -> i32x4), + "mull_s8" => p!("vmulls.v8i16", (i8x8, i8x8) -> i16x8), + "mull_s16" => p!("vmulls.v4i32", (i16x4, i16x4) -> i32x4), + "mull_s32" => p!("vmulls.v2i64", (i32x2, i32x2) -> i64x2), + "mull_u8" => p!("vmullu.v8i16", (i8x8, i8x8) -> i16x8), + "mull_u16" => p!("vmullu.v4i32", (i16x4, i16x4) -> i32x4), + "mull_u32" => p!("vmullu.v2i64", (i32x2, i32x2) -> i64x2), + "qdmull_s16" => p!("vqdmull.v4i32", (i16x4, i16x4) -> i32x4), + "qdmull_s32" => p!("vqdmull.v2i64", (i32x2, i32x2) -> i64x2), + "hsub_s8" => p!("vhsubs.v8i8", (i8x8, i8x8) -> i8x8), + "hsubq_s8" => p!("vhsubs.v16i8", (i8x16, i8x16) -> i8x16), + "hsub_s16" => p!("vhsubs.v4i16", (i16x4, i16x4) -> i16x4), + "hsubq_s16" => p!("vhsubs.v8i16", (i16x8, i16x8) -> i16x8), + "hsub_s32" => p!("vhsubs.v2i32", (i32x2, i32x2) -> i32x2), + "hsubq_s32" => p!("vhsubs.v4i32", (i32x4, i32x4) -> i32x4), + "hsub_u8" => p!("vhsubu.v8i8", (i8x8, i8x8) -> i8x8), + "hsubq_u8" => p!("vhsubu.v16i8", (i8x16, i8x16) -> i8x16), + "hsub_u16" => p!("vhsubu.v4i16", (i16x4, i16x4) -> i16x4), + "hsubq_u16" => p!("vhsubu.v8i16", (i16x8, i16x8) -> i16x8), + "hsub_u32" => p!("vhsubu.v2i32", (i32x2, i32x2) -> i32x2), + "hsubq_u32" => p!("vhsubu.v4i32", (i32x4, i32x4) -> i32x4), + "qsub_s8" => p!("vqsubs.v8i8", (i8x8, i8x8) -> i8x8), + "qsubq_s8" => p!("vqsubs.v16i8", (i8x16, i8x16) -> i8x16), + "qsub_s16" => p!("vqsubs.v4i16", (i16x4, i16x4) -> i16x4), + "qsubq_s16" => p!("vqsubs.v8i16", (i16x8, i16x8) -> i16x8), + "qsub_s32" => p!("vqsubs.v2i32", (i32x2, i32x2) -> i32x2), + "qsubq_s32" => p!("vqsubs.v4i32", (i32x4, i32x4) -> i32x4), + "qsub_s64" => p!("vqsubu.v1i64", (i64x1, i64x1) -> i64x1), + "qsubq_s64" => p!("vqsubu.v2i64", (i64x2, i64x2) -> i64x2), + "qsub_u8" => p!("vqsubu.v8i8", (i8x8, i8x8) -> i8x8), + "qsubq_u8" => p!("vqsubu.v16i8", (i8x16, i8x16) -> i8x16), + "qsub_u16" => p!("vqsubu.v4i16", (i16x4, i16x4) -> i16x4), + "qsubq_u16" => p!("vqsubu.v8i16", (i16x8, i16x8) -> i16x8), + "qsub_u32" => p!("vqsubu.v2i32", (i32x2, i32x2) -> i32x2), + "qsubq_u32" => p!("vqsubu.v4i32", (i32x4, i32x4) -> i32x4), + "qsub_u64" => p!("vqsubu.v1i64", (i64x1, i64x1) -> i64x1), + "qsubq_u64" => p!("vqsubu.v2i64", (i64x2, i64x2) -> i64x2), + "abd_s8" => p!("vabds.v8i8", (i8x8, i8x8) -> i8x8), + "abdq_s8" => p!("vabds.v16i8", (i8x16, i8x16) -> i8x16), + "abd_s16" => p!("vabds.v4i16", (i16x4, i16x4) -> i16x4), + "abdq_s16" => p!("vabds.v8i16", (i16x8, i16x8) -> i16x8), + "abd_s32" => p!("vabds.v2i32", (i32x2, i32x2) -> i32x2), + "abdq_s32" => p!("vabds.v4i32", (i32x4, i32x4) -> i32x4), + "abd_u8" => p!("vabdu.v8i8", (i8x8, i8x8) -> i8x8), + "abdq_u8" => p!("vabdu.v16i8", (i8x16, i8x16) -> i8x16), + "abd_u16" => p!("vabdu.v4i16", (i16x4, i16x4) -> i16x4), + "abdq_u16" => p!("vabdu.v8i16", (i16x8, i16x8) -> i16x8), + "abd_u32" => p!("vabdu.v2i32", (i32x2, i32x2) -> i32x2), + "abdq_u32" => p!("vabdu.v4i32", (i32x4, i32x4) -> i32x4), + "abd_f32" => p!("vabds.v2f32", (f32x2, f32x2) -> f32x2), + "abdq_f32" => p!("vabds.v4f32", (f32x4, f32x4) -> f32x4), + "max_s8" => p!("vmaxs.v8i8", (i8x8, i8x8) -> i8x8), + "maxq_s8" => p!("vmaxs.v16i8", (i8x16, i8x16) -> i8x16), + "max_s16" => p!("vmaxs.v4i16", (i16x4, i16x4) -> i16x4), + "maxq_s16" => p!("vmaxs.v8i16", (i16x8, i16x8) -> i16x8), + "max_s32" => p!("vmaxs.v2i32", (i32x2, i32x2) -> i32x2), + "maxq_s32" => p!("vmaxs.v4i32", (i32x4, i32x4) -> i32x4), + "max_u8" => p!("vmaxu.v8i8", (i8x8, i8x8) -> i8x8), + "maxq_u8" => p!("vmaxu.v16i8", (i8x16, i8x16) -> i8x16), + "max_u16" => p!("vmaxu.v4i16", (i16x4, i16x4) -> i16x4), + "maxq_u16" => p!("vmaxu.v8i16", (i16x8, i16x8) -> i16x8), + "max_u32" => p!("vmaxu.v2i32", (i32x2, i32x2) -> i32x2), + "maxq_u32" => p!("vmaxu.v4i32", (i32x4, i32x4) -> i32x4), + "max_f32" => p!("vmaxs.v2f32", (f32x2, f32x2) -> f32x2), + "maxq_f32" => p!("vmaxs.v4f32", (f32x4, f32x4) -> f32x4), + "min_s8" => p!("vmins.v8i8", (i8x8, i8x8) -> i8x8), + "minq_s8" => p!("vmins.v16i8", (i8x16, i8x16) -> i8x16), + "min_s16" => p!("vmins.v4i16", (i16x4, i16x4) -> i16x4), + "minq_s16" => p!("vmins.v8i16", (i16x8, i16x8) -> i16x8), + "min_s32" => p!("vmins.v2i32", (i32x2, i32x2) -> i32x2), + "minq_s32" => p!("vmins.v4i32", (i32x4, i32x4) -> i32x4), + "min_u8" => p!("vminu.v8i8", (i8x8, i8x8) -> i8x8), + "minq_u8" => p!("vminu.v16i8", (i8x16, i8x16) -> i8x16), + "min_u16" => p!("vminu.v4i16", (i16x4, i16x4) -> i16x4), + "minq_u16" => p!("vminu.v8i16", (i16x8, i16x8) -> i16x8), + "min_u32" => p!("vminu.v2i32", (i32x2, i32x2) -> i32x2), + "minq_u32" => p!("vminu.v4i32", (i32x4, i32x4) -> i32x4), + "min_f32" => p!("vmins.v2f32", (f32x2, f32x2) -> f32x2), + "minq_f32" => p!("vmins.v4f32", (f32x4, f32x4) -> f32x4), + "shl_s8" => p!("vshifts.v8i8", (i8x8, i8x8) -> i8x8), + "shlq_s8" => p!("vshifts.v16i8", (i8x16, i8x16) -> i8x16), + "shl_s16" => p!("vshifts.v4i16", (i16x4, i16x4) -> i16x4), + "shlq_s16" => p!("vshifts.v8i16", (i16x8, i16x8) -> i16x8), + "shl_s32" => p!("vshifts.v2i32", (i32x2, i32x2) -> i32x2), + "shlq_s32" => p!("vshifts.v4i32", (i32x4, i32x4) -> i32x4), + "shl_s64" => p!("vshiftu.v1i64", (i64x1, i64x1) -> i64x1), + "shlq_s64" => p!("vshiftu.v2i64", (i64x2, i64x2) -> i64x2), + "shl_u8" => p!("vshiftu.v8i8", (i8x8, i8x8) -> i8x8), + "shlq_u8" => p!("vshiftu.v16i8", (i8x16, i8x16) -> i8x16), + "shl_u16" => p!("vshiftu.v4i16", (i16x4, i16x4) -> i16x4), + "shlq_u16" => p!("vshiftu.v8i16", (i16x8, i16x8) -> i16x8), + "shl_u32" => p!("vshiftu.v2i32", (i32x2, i32x2) -> i32x2), + "shlq_u32" => p!("vshiftu.v4i32", (i32x4, i32x4) -> i32x4), + "shl_u64" => p!("vshiftu.v1i64", (i64x1, i64x1) -> i64x1), + "shlq_u64" => p!("vshiftu.v2i64", (i64x2, i64x2) -> i64x2), + "qshl_s8" => p!("vqshifts.v8i8", (i8x8, i8x8) -> i8x8), + "qshlq_s8" => p!("vqshifts.v16i8", (i8x16, i8x16) -> i8x16), + "qshl_s16" => p!("vqshifts.v4i16", (i16x4, i16x4) -> i16x4), + "qshlq_s16" => p!("vqshifts.v8i16", (i16x8, i16x8) -> i16x8), + "qshl_s32" => p!("vqshifts.v2i32", (i32x2, i32x2) -> i32x2), + "qshlq_s32" => p!("vqshifts.v4i32", (i32x4, i32x4) -> i32x4), + "qshl_s64" => p!("vqshiftu.v1i64", (i64x1, i64x1) -> i64x1), + "qshlq_s64" => p!("vqshiftu.v2i64", (i64x2, i64x2) -> i64x2), + "qshl_u8" => p!("vqshiftu.v8i8", (i8x8, i8x8) -> i8x8), + "qshlq_u8" => p!("vqshiftu.v16i8", (i8x16, i8x16) -> i8x16), + "qshl_u16" => p!("vqshiftu.v4i16", (i16x4, i16x4) -> i16x4), + "qshlq_u16" => p!("vqshiftu.v8i16", (i16x8, i16x8) -> i16x8), + "qshl_u32" => p!("vqshiftu.v2i32", (i32x2, i32x2) -> i32x2), + "qshlq_u32" => p!("vqshiftu.v4i32", (i32x4, i32x4) -> i32x4), + "qshl_u64" => p!("vqshiftu.v1i64", (i64x1, i64x1) -> i64x1), + "qshlq_u64" => p!("vqshiftu.v2i64", (i64x2, i64x2) -> i64x2), + "rshl_s8" => p!("vrshifts.v8i8", (i8x8, i8x8) -> i8x8), + "rshlr_s8" => p!("vrshifts.v16i8", (i8x16, i8x16) -> i8x16), + "rshl_s16" => p!("vrshifts.v4i16", (i16x4, i16x4) -> i16x4), + "rshlr_s16" => p!("vrshifts.v8i16", (i16x8, i16x8) -> i16x8), + "rshl_s32" => p!("vrshifts.v2i32", (i32x2, i32x2) -> i32x2), + "rshlr_s32" => p!("vrshifts.v4i32", (i32x4, i32x4) -> i32x4), + "rshl_s64" => p!("vrshiftu.v1i64", (i64x1, i64x1) -> i64x1), + "rshlr_s64" => p!("vrshiftu.v2i64", (i64x2, i64x2) -> i64x2), + "rshl_u8" => p!("vrshiftu.v8i8", (i8x8, i8x8) -> i8x8), + "rshlr_u8" => p!("vrshiftu.v16i8", (i8x16, i8x16) -> i8x16), + "rshl_u16" => p!("vrshiftu.v4i16", (i16x4, i16x4) -> i16x4), + "rshlr_u16" => p!("vrshiftu.v8i16", (i16x8, i16x8) -> i16x8), + "rshl_u32" => p!("vrshiftu.v2i32", (i32x2, i32x2) -> i32x2), + "rshlr_u32" => p!("vrshiftu.v4i32", (i32x4, i32x4) -> i32x4), + "rshl_u64" => p!("vrshiftu.v1i64", (i64x1, i64x1) -> i64x1), + "rshlr_u64" => p!("vrshiftu.v2i64", (i64x2, i64x2) -> i64x2), + "qrshl_s8" => p!("vqrshifts.v8i8", (i8x8, i8x8) -> i8x8), + "qrshlqr_s8" => p!("vqrshifts.v16i8", (i8x16, i8x16) -> i8x16), + "qrshl_s16" => p!("vqrshifts.v4i16", (i16x4, i16x4) -> i16x4), + "qrshlqr_s16" => p!("vqrshifts.v8i16", (i16x8, i16x8) -> i16x8), + "qrshl_s32" => p!("vqrshifts.v2i32", (i32x2, i32x2) -> i32x2), + "qrshlqr_s32" => p!("vqrshifts.v4i32", (i32x4, i32x4) -> i32x4), + "qrshl_s64" => p!("vqrshiftu.v1i64", (i64x1, i64x1) -> i64x1), + "qrshlqr_s64" => p!("vqrshiftu.v2i64", (i64x2, i64x2) -> i64x2), + "qrshl_u8" => p!("vqrshiftu.v8i8", (i8x8, i8x8) -> i8x8), + "qrshlqr_u8" => p!("vqrshiftu.v16i8", (i8x16, i8x16) -> i8x16), + "qrshl_u16" => p!("vqrshiftu.v4i16", (i16x4, i16x4) -> i16x4), + "qrshlqr_u16" => p!("vqrshiftu.v8i16", (i16x8, i16x8) -> i16x8), + "qrshl_u32" => p!("vqrshiftu.v2i32", (i32x2, i32x2) -> i32x2), + "qrshlqr_u32" => p!("vqrshiftu.v4i32", (i32x4, i32x4) -> i32x4), + "qrshl_u64" => p!("vqrshiftu.v1i64", (i64x1, i64x1) -> i64x1), + "qrshlqr_u64" => p!("vqrshiftu.v2i64", (i64x2, i64x2) -> i64x2), + "qmovn_s16" => p!("vqmovns.v8i8", (i16x8) -> i8x8), + "qmovn_s32" => p!("vqmovns.v4i16", (i32x4) -> i16x4), + "qmovn_s64" => p!("vqmovns.v2i32", (i64x2) -> i32x2), + "qmovn_u16" => p!("vqmovnu.v8i8", (i16x8) -> i8x8), + "qmovn_u32" => p!("vqmovnu.v4i16", (i32x4) -> i16x4), + "qmovn_u64" => p!("vqmovnu.v2i32", (i64x2) -> i32x2), + "qmovun_s16" => p!("vqmovnsu.v8i8", (i16x8) -> i8x8), + "qmovun_s32" => p!("vqmovnsu.v4i16", (i32x4) -> i16x4), + "qmovun_s64" => p!("vqmovnsu.v2i32", (i64x2) -> i32x2), + "abs_s8" => p!("vabs.v8i8", (i8x8, i8x8) -> i8x8), + "absq_s8" => p!("vabs.v16i8", (i8x16, i8x16) -> i8x16), + "abs_s16" => p!("vabs.v4i16", (i16x4, i16x4) -> i16x4), + "absq_s16" => p!("vabs.v8i16", (i16x8, i16x8) -> i16x8), + "abs_s32" => p!("vabs.v2i32", (i32x2, i32x2) -> i32x2), + "absq_s32" => p!("vabs.v4i32", (i32x4, i32x4) -> i32x4), + "abs_f32" => p!("vabs.v2f32", (f32x2, f32x2) -> f32x2), + "absq_f32" => p!("vabs.v4f32", (f32x4, f32x4) -> f32x4), + "qabs_s8" => p!("vqabs.v8i8", (i8x8, i8x8) -> i8x8), + "qabsq_s8" => p!("vqabs.v16i8", (i8x16, i8x16) -> i8x16), + "qabs_s16" => p!("vqabs.v4i16", (i16x4, i16x4) -> i16x4), + "qabsq_s16" => p!("vqabs.v8i16", (i16x8, i16x8) -> i16x8), + "qabs_s32" => p!("vqabs.v2i32", (i32x2, i32x2) -> i32x2), + "qabsq_s32" => p!("vqabs.v4i32", (i32x4, i32x4) -> i32x4), + "neg_s8" => p!("vneg.v8i8", (i8x8) -> i8x8), + "negq_s8" => p!("vneg.v16i8", (i8x16) -> i8x16), + "neg_s16" => p!("vneg.v4i16", (i16x4) -> i16x4), + "negq_s16" => p!("vneg.v8i16", (i16x8) -> i16x8), + "neg_s32" => p!("vneg.v2i32", (i32x2) -> i32x2), + "negq_s32" => p!("vneg.v4i32", (i32x4) -> i32x4), + "neg_f32" => p!("vneg.v2f32", (f32x2) -> f32x2), + "negq_f32" => p!("vneg.v4f32", (f32x4) -> f32x4), + "qneg_s8" => p!("vqneg.v8i8", (i8x8) -> i8x8), + "qnegq_s8" => p!("vqneg.v16i8", (i8x16) -> i8x16), + "qneg_s16" => p!("vqneg.v4i16", (i16x4) -> i16x4), + "qnegq_s16" => p!("vqneg.v8i16", (i16x8) -> i16x8), + "qneg_s32" => p!("vqneg.v2i32", (i32x2) -> i32x2), + "qnegq_s32" => p!("vqneg.v4i32", (i32x4) -> i32x4), + "cls_s8" => p!("vcls.v8i8", (i8x8) -> i8x8), + "clsq_s8" => p!("vcls.v16i8", (i8x16) -> i8x16), + "cls_s16" => p!("vcls.v4i16", (i16x4) -> i16x4), + "clsq_s16" => p!("vcls.v8i16", (i16x8) -> i16x8), + "cls_s32" => p!("vcls.v2i32", (i32x2) -> i32x2), + "clsq_s32" => p!("vcls.v4i32", (i32x4) -> i32x4), + "clz_s8" => p!("vclz.v8i8", (i8x8) -> i8x8), + "clzq_s8" => p!("vclz.v16i8", (i8x16) -> i8x16), + "clz_s16" => p!("vclz.v4i16", (i16x4) -> i16x4), + "clzq_s16" => p!("vclz.v8i16", (i16x8) -> i16x8), + "clz_s32" => p!("vclz.v2i32", (i32x2) -> i32x2), + "clzq_s32" => p!("vclz.v4i32", (i32x4) -> i32x4), + "cnt_s8" => p!("vcnt.v8i8", (i8x8) -> i8x8), + "cntq_s8" => p!("vcnt.v16i8", (i8x16) -> i8x16), + "recpe_u32" => p!("vrecpe.v2i32", (i32x2) -> i32x2), + "recpeq_u32" => p!("vrecpe.v4i32", (i32x4) -> i32x4), + "recpe_f32" => p!("vrecpe.v2f32", (f32x2) -> f32x2), + "recpeq_f32" => p!("vrecpe.v4f32", (f32x4) -> f32x4), + "recps_f32" => p!("vrecps.v2f32", (f32x2, f32x2) -> f32x2), + "recpsq_f32" => p!("vrecps.v4f32", (f32x4, f32x4) -> f32x4), + "rsqrte_u32" => p!("vrsqrte.v2i32", (i32x2) -> i32x2), + "rsqrteq_u32" => p!("vrsqrte.v4i32", (i32x4) -> i32x4), + "rsqrte_f32" => p!("vrsqrte.v2f32", (f32x2) -> f32x2), + "rsqrteq_f32" => p!("vrsqrte.v4f32", (f32x4) -> f32x4), + "rsqrts_f32" => p!("vrsqrts.v2f32", (f32x2, f32x2) -> f32x2), + "rsqrtsq_f32" => p!("vrsqrts.v4f32", (f32x4, f32x4) -> f32x4), + "bsl_s8" => p!("vsl.v8i8", (i8x8, i8x8, i8x8) -> i8x8), + "bslq_s8" => p!("vsl.v16i8", (i8x16, i8x16, i8x16) -> i8x16), + "padd_s8" => p!("vpadd.v8i8", (i8x8, i8x8) -> i8x8), + "padd_s16" => p!("vpadd.v4i16", (i16x4, i16x4) -> i16x4), + "padd_s32" => p!("vpadd.v2i32", (i32x2, i32x2) -> i32x2), + "padd_u8" => p!("vpadd.v8i8", (i8x8, i8x8) -> i8x8), + "padd_u16" => p!("vpadd.v4i16", (i16x4, i16x4) -> i16x4), + "padd_u32" => p!("vpadd.v2i32", (i32x2, i32x2) -> i32x2), + "padd_f32" => p!("vpadd.v2f32", (f32x2, f32x2) -> f32x2), + "paddl_s8" => p!("vpaddls.v4i16.v8i8", (i8x8) -> i16x4), + "paddlq_s8" => p!("vpaddls.v8i16.v16i8", (i8x16) -> i16x8), + "paddl_s16" => p!("vpaddls.v2i32.v4i16", (i16x4) -> i32x2), + "paddlq_s16" => p!("vpaddls.v4i32.v8i16", (i16x8) -> i32x4), + "paddl_s32" => p!("vpaddls.v1i64.v2i32", (i32x2) -> i64x1), + "paddlq_s32" => p!("vpaddls.v2i64.v4i32", (i32x4) -> i64x2), + "paddl_u8" => p!("vpaddlu.v4i16.v8i8", (i8x8) -> i16x4), + "paddlq_u8" => p!("vpaddlu.v8i16.v16i8", (i8x16) -> i16x8), + "paddl_u16" => p!("vpaddlu.v2i32.v4i16", (i16x4) -> i32x2), + "paddlq_u16" => p!("vpaddlu.v4i32.v8i16", (i16x8) -> i32x4), + "paddl_u32" => p!("vpaddlu.v1i64.v2i32", (i32x2) -> i64x1), + "paddlq_u32" => p!("vpaddlu.v2i64.v4i32", (i32x4) -> i64x2), + "padal_s8" => p!("vpadals.v4i16.v8i8", (i16x4, i8x8) -> i16x4), + "padalq_s8" => p!("vpadals.v8i16.v16i8", (i16x8, i8x16) -> i16x8), + "padal_s16" => p!("vpadals.v2i32.v4i16", (i32x2, i16x4) -> i32x2), + "padalq_s16" => p!("vpadals.v4i32.v8i16", (i32x4, i16x8) -> i32x4), + "padal_s32" => p!("vpadals.v1i64.v2i32", (i64x1, i32x2) -> i64x1), + "padalq_s32" => p!("vpadals.v2i64.v4i32", (i64x2, i32x4) -> i64x2), + "padal_u8" => p!("vpadalu.v4i16.v8i8", (i16x4, i8x8) -> i16x4), + "padalq_u8" => p!("vpadalu.v8i16.v16i8", (i16x8, i8x16) -> i16x8), + "padal_u16" => p!("vpadalu.v2i32.v4i16", (i32x2, i16x4) -> i32x2), + "padalq_u16" => p!("vpadalu.v4i32.v8i16", (i32x4, i16x8) -> i32x4), + "padal_u32" => p!("vpadalu.v1i64.v2i32", (i64x1, i32x2) -> i64x1), + "padalq_u32" => p!("vpadalu.v2i64.v4i32", (i64x2, i32x4) -> i64x2), + "pmax_s16" => p!("vpmaxs.v4i16", (i16x4, i16x4) -> i16x4), + "pmax_s32" => p!("vpmaxs.v2i32", (i32x2, i32x2) -> i32x2), + "pmax_s8" => p!("vpmaxs.v8i8", (i8x8, i8x8) -> i8x8), + "pmax_u16" => p!("vpmaxu.v4i16", (i16x4, i16x4) -> i16x4), + "pmax_u32" => p!("vpmaxu.v2i32", (i32x2, i32x2) -> i32x2), + "pmax_u8" => p!("vpmaxu.v8i8", (i8x8, i8x8) -> i8x8), + "pmin_s16" => p!("vpmins.v4i16", (i16x4, i16x4) -> i16x4), + "pmin_s32" => p!("vpmins.v2i32", (i32x2, i32x2) -> i32x2), + "pmin_s8" => p!("vpmins.v8i8", (i8x8, i8x8) -> i8x8), + "pmin_u16" => p!("vpminu.v4i16", (i16x4, i16x4) -> i16x4), + "pmin_u32" => p!("vpminu.v2i32", (i32x2, i32x2) -> i32x2), + "pmin_u8" => p!("vpminu.v8i8", (i8x8, i8x8) -> i8x8), + "tbl1_s8" => p!("vtbl1", (i8x8, i8x8) -> i8x8), + "tbl1_u8" => p!("vtbl1", (i8x8, i8x8) -> i8x8), + // these aren't exactly the C intrinsics (they take one argument) + "tbl2_s8" => p!("vtbl2", (i8x8, i8x8, i8x8) -> i8x8), + "tbl2_u8" => p!("vtbl2", (i8x8, i8x8, i8x8) -> i8x8), + "tbl3_s8" => p!("vtbl3", (i8x8, i8x8, i8x8, i8x8) -> i8x8), + "tbl3_u8" => p!("vtbl3", (i8x8, i8x8, i8x8, i8x8) -> i8x8), + "tbl4_s8" => p!("vtbl4", (i8x8, i8x8, i8x8, i8x8, i8x8) -> i8x8), + "tbl4_u8" => p!("vtbl4", (i8x8, i8x8, i8x8, i8x8, i8x8) -> i8x8), + "tbx1_s8" => p!("vtbx1", (i8x8, i8x8, i8x8) -> i8x8), + "tbx1_u8" => p!("vtbx1", (i8x8, i8x8, i8x8) -> i8x8), + "tbx2_s8" => p!("vtbx2", (i8x8, i8x8, i8x8, i8x8) -> i8x8), + "tbx2_u8" => p!("vtbx2", (i8x8, i8x8, i8x8, i8x8) -> i8x8), + "tbx3_s8" => p!("vtbx3", (i8x8, i8x8, i8x8, i8x8, i8x8) -> i8x8), + "tbx3_u8" => p!("vtbx3", (i8x8, i8x8, i8x8, i8x8, i8x8) -> i8x8), + "tbx4_s8" => p!("vtbx4", (i8x8, i8x8, i8x8, i8x8, i8x8, i8x8) -> i8x8), + "tbx4_u8" => p!("vtbx4", (i8x8, i8x8, i8x8, i8x8, i8x8, i8x8) -> i8x8), + _ => return None, + }) +} diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs new file mode 100755 index 0000000000000..134b4c66419b6 --- /dev/null +++ b/src/librustc_platform_intrinsics/lib.rs @@ -0,0 +1,103 @@ +// 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. + +#![cfg_attr(stage0, feature(custom_attribute))] +#![crate_name = "rustc_platform_intrinsics"] +#![unstable(feature = "rustc_private", issue = "27812")] +#![staged_api] +#![crate_type = "dylib"] +#![crate_type = "rlib"] +#![feature(staged_api, rustc_private)] + +extern crate rustc_llvm as llvm; +extern crate rustc; + +use rustc::middle::ty; + +pub struct Intrinsic { + pub inputs: Vec, + pub output: Type, + + pub definition: IntrinsicDef, +} + +#[derive(Clone, Hash, Eq, PartialEq)] +pub enum Type { + Integer(u8), + Float(u8), + Pointer(Box), + Vector(Box, u8), +} + +pub enum IntrinsicDef { + Named(&'static str), +} + +fn i(width: u8) -> Type { Type::Integer(width) } +fn f(width: u8) -> Type { Type::Float(width) } +fn v(x: Type, length: u8) -> Type { Type::Vector(Box::new(x), length) } + +macro_rules! ty { + (f32x8) => (v(f(32), 8)); + (f64x4) => (v(f(64), 4)); + + (i8x32) => (v(i(8), 32)); + (i16x16) => (v(i(16), 16)); + (i32x8) => (v(i(32), 8)); + (i64x4) => (v(i(64), 4)); + + (f32x4) => (v(f(32), 4)); + (f64x2) => (v(f(64), 2)); + + (i8x16) => (v(i(8), 16)); + (i16x8) => (v(i(16), 8)); + (i32x4) => (v(i(32), 4)); + (i64x2) => (v(i(64), 2)); + + (f32x2) => (v(f(32), 2)); + (i8x8) => (v(i(8), 8)); + (i16x4) => (v(i(16), 4)); + (i32x2) => (v(i(32), 2)); + (i64x1)=> (v(i(64), 1)); + + (i64) => (i(64)); + (i32) => (i(32)); + (i16) => (i(16)); + (i8) => (i(8)); + (f32) => (f(32)); + (f64) => (f(64)); +} +macro_rules! plain { + ($name: expr, ($($inputs: tt),*) -> $output: tt) => { + Intrinsic { + inputs: vec![$(ty!($inputs)),*], + output: ty!($output), + definition: ::IntrinsicDef::Named($name) + } + } +} + +mod x86; +mod arm; +mod aarch64; + +impl Intrinsic { + pub fn find<'tcx>(tcx: &ty::ctxt<'tcx>, name: &str) -> Option { + if name.starts_with("x86_") { + x86::find(tcx, &name["x86_".len()..]) + } else if name.starts_with("arm_") { + arm::find(tcx, &name["arm_".len()..]) + } else if name.starts_with("aarch64_") { + aarch64::find(tcx, &name["aarch64_".len()..]) + } else { + None + } + } +} diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs new file mode 100644 index 0000000000000..cab7ab2fecb82 --- /dev/null +++ b/src/librustc_platform_intrinsics/x86.rs @@ -0,0 +1,188 @@ +// 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. + +use {Intrinsic, i, f, v}; +use rustc::middle::ty; + +macro_rules! p { + ($name: expr, ($($inputs: tt),*) -> $output: tt) => { + plain!(concat!("llvm.x86.", $name), ($($inputs),*) -> $output) + } +} + +pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { + if name.starts_with("mm_") { + Some(match &name["mm_".len()..] { + "sqrt_ps" => plain!("llvm.sqrt.v4f32", (f32x4) -> f32x4), + "sqrt_pd" => plain!("llvm.sqrt.v2f64", (f64x2) -> f64x2), + + "movemask_ps" => p!("sse.movmsk.ps", (f32x4) -> i32), + "max_ps" => p!("sse.max.ps", (f32x4, f32x4) -> f32x4), + "min_ps" => p!("sse.min.ps", (f32x4, f32x4) -> f32x4), + "rsqrt_ps" => p!("sse.rsqrt.ps", (f32x4) -> f32x4), + "rcp_ps" => p!("sse.rcp.ps", (f32x4) -> f32x4), + + "adds_epi16" => p!("sse2.padds.w", (i16x8, i16x8) -> i16x8), + "adds_epi8" => p!("sse2.padds.b", (i8x16, i8x16) -> i8x16), + "adds_epu16" => p!("sse2.paddus.w", (i16x8, i16x8) -> i16x8), + "adds_epu8" => p!("sse2.paddus.b", (i8x16, i8x16) -> i8x16), + "avg_epu16" => p!("sse2.pavg.w", (i16x8, i16x8) -> i16x8), + "avg_epu8" => p!("sse2.pavg.b", (i8x16, i8x16) -> i8x16), + "madd_epi16" => p!("sse2.pmadd.wd", (i16x8, i16x8) -> i32x4), + "max_epi16" => p!("sse2.pmaxs.w", (i16x8, i16x8) -> i16x8), + "max_epu8" => p!("sse2.pmaxu.b", (i8x16, i8x16) -> i8x16), + "max_pd" => p!("sse2.max.pd", (f64x2, f64x2) -> f64x2), + "min_epi16" => p!("sse2.pmins.w", (i16x8, i16x8) -> i16x8), + "min_epu8" => p!("sse2.pminu.b", (i8x16, i8x16) -> i8x16), + "min_pd" => p!("sse2.min.pd", (f64x2, f64x2) -> f64x2), + "movemask_pd" => p!("sse2.movmsk.pd", (f64x2) -> i32), + "movemask_epi8" => p!("sse2.pmovmskb.128", (i8x16) -> i32), + "mul_epu32" => p!("sse2.pmulu.dq", (i32x4, i32x4) -> i64x2), + "mulhi_epi16" => p!("sse2.pmulh.w", (i8x16, i8x16) -> i8x16), + "mulhi_epu16" => p!("sse2.pmulhu.w", (i8x16, i8x16) -> i8x16), + "packs_epi16" => p!("sse2.packsswb.128", (i16x8, i16x8) -> i8x16), + "packs_epi32" => p!("sse2.packssdw.128", (i32x4, i32x4) -> i16x8), + "packus_epi16" => p!("sse2.packuswb.128", (i16x8, i16x8) -> i8x16), + "sad_epu8" => p!("sse2.psad.bw", (i8x16, i8x16) -> i64x2), + "subs_epi16" => p!("sse2.psubs.w", (i16x8, i16x8) -> i16x8), + "subs_epi8" => p!("sse2.psubs.b", (i8x16, i8x16) -> i8x16), + "subs_epu16" => p!("sse2.psubus.w", (i16x8, i16x8) -> i16x8), + "subs_epu8" => p!("sse2.psubus.b", (i8x16, i8x16) -> i8x16), + + "addsub_pd" => p!("sse3.addsub.pd", (f64x2, f64x2) -> f64x2), + "addsub_ps" => p!("sse3.addsub.ps", (f32x4, f32x4) -> f32x4), + "hadd_pd" => p!("sse3.hadd.pd", (f64x2, f64x2) -> f64x2), + "hadd_ps" => p!("sse3.hadd.ps", (f32x4, f32x4) -> f32x4), + "hsub_pd" => p!("sse3.hsub.pd", (f64x2, f64x2) -> f64x2), + "hsub_ps" => p!("sse3.hsub.ps", (f32x4, f32x4) -> f32x4), + + "abs_epi16" => p!("ssse3.pabs.w.128", (i16x8) -> i16x8), + "abs_epi32" => p!("ssse3.pabs.d.128", (i32x4) -> i32x4), + "abs_epi8" => p!("ssse3.pabs.b.128", (i8x16) -> i8x16), + "hadd_epi16" => p!("ssse3.phadd.w.128", (i16x8, i16x8) -> i16x8), + "hadd_epi32" => p!("ssse3.phadd.d.128", (i32x4, i32x4) -> i32x4), + "hadds_epi16" => p!("ssse3.phadd.sw.128", (i16x8, i16x8) -> i16x8), + "hsub_epi16" => p!("ssse3.phsub.w.128", (i16x8, i16x8) -> i16x8), + "hsub_epi32" => p!("ssse3.phsub.d.128", (i32x4, i32x4) -> i32x4), + "hsubs_epi16" => p!("ssse3.phsub.sw.128", (i16x8, i16x8) -> i16x8), + "maddubs_epi16" => p!("ssse3.pmadd.ub.sw.128", (i8x16, i8x16) -> i16x8), + "mulhrs_epi16" => p!("ssse3.pmul.hr.sw.128", (i16x8, i16x8) -> i16x8), + "shuffle_epi8" => p!("ssse3.pshuf.b.128", (i8x16, i8x16) -> i8x16), + "sign_epi16" => p!("ssse3.psign.w.128", (i16x8, i16x8) -> i16x8), + "sign_epi32" => p!("ssse3.psign.d.128", (i32x4, i32x4) -> i32x4), + "sign_epi8" => p!("ssse3.psign.b.128", (i8x16, i8x16) -> i8x16), + + "max_epi32" => p!("sse41.pmaxsd", (i32x4, i32x4) -> i32x4), + "max_epi8" => p!("sse41.pmaxsb", (i8x16, i8x16) -> i8x16), + "max_epu16" => p!("sse41.pmaxuw", (i16x8, i16x8) -> i16x8), + "max_epu32" => p!("sse41.pmaxud", (i32x4, i32x4) -> i32x4), + "min_epi32" => p!("sse41.pminsd", (i32x4, i32x4) -> i32x4), + "min_epi8" => p!("sse41.pminsb", (i8x16, i8x16) -> i8x16), + "min_epu16" => p!("sse41.pminuw", (i16x8, i16x8) -> i16x8), + "min_epu32" => p!("sse41.pminud", (i32x4, i32x4) -> i32x4), + "minpos_epu16" => p!("sse41.phminposuw", (i16x8) -> i16x8), + "mul_epi32" => p!("sse41.muldq", (i32x4, i32x4) -> i64x2), + "packus_epi32" => p!("sse41.packusdw", (i32x4, i32x4) -> i16x8), + "testc_si128" => p!("sse41.ptestc", (i64x2, i64x2) -> i32), + "testnzc_si128" => p!("sse41.ptestnzc", (i64x2, i64x2) -> i32), + "testz_si128" => p!("sse41.ptestz", (i64x2, i64x2) -> i32), + + "permutevar_pd" => p!("avx.vpermilvar.pd", (f64x2, i64x2) -> f64x2), + "permutevar_ps" => p!("avx.vpermilvar.ps", (f32x4, i32x4) -> f32x4), + "testc_pd" => p!("avx.vtestc.pd", (f64x2, f64x2) -> i32), + "testc_ps" => p!("avx.vtestc.ps", (f32x4, f32x4) -> i32), + "testnzc_pd" => p!("avx.vtestnzc.pd", (f64x2, f64x2) -> i32), + "testnzc_ps" => p!("avx.vtestnzc.ps", (f32x4, f32x4) -> i32), + "testz_pd" => p!("avx.vtestz.pd", (f64x2, f64x2) -> i32), + "testz_ps" => p!("avx.vtestz.ps", (f32x4, f32x4) -> i32), + + _ => return None + }) + } else if name.starts_with("mm256_") { + Some(match &name["mm256_".len()..] { + "addsub_pd" => p!("avx.addsub.pd.256", (f64x4, f64x4) -> f64x4), + "addsub_ps" => p!("avx.addsub.ps.256", (f32x8, f32x8) -> f32x8), + "hadd_pd" => p!("avx.hadd.pd.256", (f64x4, f64x4) -> f64x4), + "hadd_ps" => p!("avx.hadd.ps.256", (f32x8, f32x8) -> f32x8), + "hsub_pd" => p!("avx.hsub.pd.256", (f64x4, f64x4) -> f64x4), + "hsub_ps" => p!("avx.hsub.ps.256", (f32x8, f32x8) -> f32x8), + "max_pd" => p!("avx.max.pd.256", (f64x4, f64x4) -> f64x4), + "max_ps" => p!("avx.max.ps.256", (f32x8, f32x8) -> f32x8), + "min_pd" => p!("avx.min.pd.256", (f64x4, f64x4) -> f64x4), + "min_ps" => p!("avx.min.ps.256", (f32x8, f32x8) -> f32x8), + "permutevar_pd" => p!("avx.vpermilvar.pd.256", (f64x4, i64x4) -> f64x4), + "permutevar_ps" => p!("avx.vpermilvar.ps.256", (f32x8, i32x8) -> f32x8), + "rcp_ps" => p!("avx.rcp.ps.256", (f32x8) -> f32x8), + "rsqrt_ps" => p!("avx.rsqrt.ps.256", (f32x8) -> f32x8), + "sqrt_pd" => p!("llvm.sqrt.v4f64", (f64x4) -> f64x4), + "sqrt_ps" => p!("llvm.sqrt.v8f32", (f32x8) -> f32x8), + "testc_pd" => p!("avx.vtestc.pd.256", (f64x4, f64x4) -> i32), + "testc_ps" => p!("avx.vtestc.ps.256", (f32x8, f32x8) -> i32), + "testnzc_pd" => p!("avx.vtestnzc.pd.256", (f64x4, f64x4) -> i32), + "testnzc_ps" => p!("avx.vtestnzc.ps.256", (f32x8, f32x8) -> i32), + "testz_pd" => p!("avx.vtestz.pd.256", (f64x4, f64x4) -> i32), + "testz_ps" => p!("avx.vtestz.ps.256", (f32x8, f32x8) -> i32), + + "abs_epi16" => p!("avx2.pabs.w", (i16x16) -> i16x16), + "abs_epi32" => p!("avx2.pabs.d", (i32x8) -> i32x8), + "abs_epi8" => p!("avx2.pabs.b", (i8x32) -> i8x32), + "adds_epi16" => p!("avx2.padds.w", (i16x16, i16x16) -> i16x16), + "adds_epi8" => p!("avx2.padds.b", (i8x32, i8x32) -> i8x32), + "adds_epu16" => p!("avx2.paddus.w", (i16x16, i16x16) -> i16x16), + "adds_epu8" => p!("avx2.paddus.b", (i8x32, i8x32) -> i8x32), + "avg_epu16" => p!("avx2.pavg.w", (i16x16, i16x16) -> i16x16), + "avg_epu8" => p!("avx2.pavg.b", (i8x32, i8x32) -> i8x32), + "hadd_epi16" => p!("avx2.phadd.w", (i16x16, i16x16) -> i16x16), + "hadd_epi32" => p!("avx2.phadd.d", (i32x8, i32x8) -> i32x8), + "hadds_epi16" => p!("avx2.phadd.sw", (i16x16, i16x16) -> i16x16), + "hsub_epi16" => p!("avx2.phsub.w", (i16x16, i16x16) -> i16x16), + "hsub_epi32" => p!("avx2.phsub.d", (i32x8, i32x8) -> i32x8), + "hsubs_epi16" => p!("avx2.phsub.sw", (i16x16, i16x16) -> i16x16), + "madd_epi16" => p!("avx2.pmadd.wd", (i16x16, i16x16) -> i32x8), + "maddubs_epi16" => p!("avx2.pmadd.ub.sw", (i8x32, i8x32) -> i16x16), + "max_epi16" => p!("avx2.pmaxs.w", (i16x16, i16x16) -> i16x16), + "max_epi32" => p!("avx2.pmaxs.d", (i32x8, i32x8) -> i32x8), + "max_epi8" => p!("avx2.pmaxs.b", (i8x32, i8x32) -> i8x32), + "max_epu16" => p!("avx2.pmaxu.w", (i16x16, i16x16) -> i16x16), + "max_epu32" => p!("avx2.pmaxu.d", (i32x8, i32x8) -> i32x8), + "max_epu8" => p!("avx2.pmaxu.b", (i8x32, i8x32) -> i8x32), + "min_epi16" => p!("avx2.pmins.w", (i16x16, i16x16) -> i16x16), + "min_epi32" => p!("avx2.pmins.d", (i32x8, i32x8) -> i32x8), + "min_epi8" => p!("avx2.pmins.b", (i8x32, i8x32) -> i8x32), + "min_epu16" => p!("avx2.pminu.w", (i16x16, i16x16) -> i16x16), + "min_epu32" => p!("avx2.pminu.d", (i32x8, i32x8) -> i32x8), + "min_epu8" => p!("avx2.pminu.b", (i8x32, i8x32) -> i8x32), + "mul_epi32" => p!("avx2.mul.dq", (i32x8, i32x8) -> i64x4), + "mul_epu32" => p!("avx2.mulu.dq", (i32x8, i32x8) -> i64x4), + "mulhi_epi16" => p!("avx2.pmulh.w", (i8x32, i8x32) -> i8x32), + "mulhi_epu16" => p!("avx2.pmulhu.w", (i8x32, i8x32) -> i8x32), + "mulhrs_epi16" => p!("avx2.pmul.hr.sw", (i16x16, i16x16) -> i16x16), + "packs_epi16" => p!("avx2.packsswb", (i16x16, i16x16) -> i8x32), + "packs_epi32" => p!("avx2.packssdw", (i32x8, i32x8) -> i16x16), + "packus_epi16" => p!("avx2.packuswb", (i16x16, i16x16) -> i8x32), + "packus_epi32" => p!("avx2.packusdw", (i32x8, i32x8) -> i16x16), + "permutevar8x32_epi32" => p!("avx2.permd", (i32x8, i32x8) -> i32x8), + "permutevar8x32_ps" => p!("avx2.permps", (f32x8, i32x8) -> i32x8), + "sad_epu8" => p!("avx2.psad.bw", (i8x32, i8x32) -> i64x4), + "shuffle_epi8" => p!("avx2.pshuf.b", (i8x32, i8x32) -> i8x32), + "sign_epi16" => p!("avx2.psign.w", (i16x16, i16x16) -> i16x16), + "sign_epi32" => p!("avx2.psign.d", (i32x8, i32x8) -> i32x8), + "sign_epi8" => p!("avx2.psign.b", (i8x32, i8x32) -> i8x32), + "subs_epi16" => p!("avx2.psubs.w", (i16x16, i16x16) -> i16x16), + "subs_epi8" => p!("avx2.psubs.b", (i8x32, i8x32) -> i8x32), + "subs_epu16" => p!("avx2.psubus.w", (i16x16, i16x16) -> i16x16), + "subs_epu8" => p!("avx2.psubus.b", (i8x32, i8x32) -> i8x32), + + _ => return None, + }) + } else { + None + } +} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 6d91ae6fed639..23f21f337f302 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -54,6 +54,7 @@ extern crate libc; extern crate rustc; extern crate rustc_back; extern crate rustc_llvm as llvm; +extern crate rustc_platform_intrinsics as intrinsics; extern crate serialize; #[macro_use] extern crate log; diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 326d1e2361e6d..0d34cce919a64 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -615,6 +615,9 @@ fn range_to_inttype(cx: &CrateContext, hint: Hint, bounds: &IntBounds) -> IntTyp attr::ReprPacked => { cx.tcx().sess.bug("range_to_inttype: found ReprPacked on an enum"); } + attr::ReprSimd => { + cx.tcx().sess.bug("range_to_inttype: found ReprSimd on an enum"); + } } for &ity in attempts { if bounds_usable(cx, ity, bounds) { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 1982f04195f0b..6be2bb0846463 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -91,7 +91,7 @@ use std::collections::{HashMap, HashSet}; use std::mem; use std::str; use std::{i8, i16, i32, i64}; -use syntax::abi::{Rust, RustCall, RustIntrinsic, Abi}; +use syntax::abi::{Rust, RustCall, RustIntrinsic, PlatformIntrinsic, Abi}; use syntax::ast_util::local_def; use syntax::attr::AttrMetaMethods; use syntax::attr; @@ -348,17 +348,14 @@ pub fn compare_simd_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, lhs: ValueRef, rhs: ValueRef, t: Ty<'tcx>, + ret_ty: Type, op: ast::BinOp_, debug_loc: DebugLoc) -> ValueRef { let signed = match t.sty { ty::TyFloat(_) => { - // The comparison operators for floating point vectors are challenging. - // LLVM outputs a `< size x i1 >`, but if we perform a sign extension - // then bitcast to a floating point vector, the result will be `-NaN` - // for each truth value. Because of this they are unsupported. - bcx.sess().bug("compare_simd_types: comparison operators \ - not supported for floating point SIMD types") + let cmp = bin_op_to_fcmp_predicate(bcx.ccx(), op); + return SExt(bcx, FCmp(bcx, cmp, lhs, rhs, debug_loc), ret_ty); }, ty::TyUint(_) => false, ty::TyInt(_) => true, @@ -370,7 +367,7 @@ pub fn compare_simd_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // to get the correctly sized type. This will compile to a single instruction // once the IR is converted to assembly if the SIMD instruction is supported // by the target architecture. - SExt(bcx, ICmp(bcx, cmp, lhs, rhs, debug_loc), val_ty(lhs)) + SExt(bcx, ICmp(bcx, cmp, lhs, rhs, debug_loc), ret_ty) } // Iterates through the elements of a structural type. @@ -674,7 +671,7 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, Rust | RustCall => { get_extern_rust_fn(ccx, t, &name[..], did) } - RustIntrinsic => { + RustIntrinsic | PlatformIntrinsic => { ccx.sess().bug("unexpected intrinsic in trans_external_path") } _ => { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index d0d5b46ab2839..d201114fd82f9 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -150,7 +150,8 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) } } def::DefFn(did, _) if match expr_ty.sty { - ty::TyBareFn(_, ref f) => f.abi == synabi::RustIntrinsic, + ty::TyBareFn(_, ref f) => f.abi == synabi::RustIntrinsic || + f.abi == synabi::PlatformIntrinsic, _ => false } => { let substs = common::node_id_substs(bcx.ccx(), @@ -671,7 +672,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, (d.llfn, Some(d.llself)) } Intrinsic(node, substs) => { - assert!(abi == synabi::RustIntrinsic); + assert!(abi == synabi::RustIntrinsic || abi == synabi::PlatformIntrinsic); assert!(dest.is_some()); let call_info = match debug_loc { @@ -701,7 +702,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, // Intrinsics should not become actual functions. // We trans them in place in `trans_intrinsic_call` - assert!(abi != synabi::RustIntrinsic); + assert!(abi != synabi::RustIntrinsic && abi != synabi::PlatformIntrinsic); let is_rust_fn = abi == synabi::Rust || abi == synabi::RustCall; diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index c5043f867ded0..9ba45e0d481a3 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -1797,7 +1797,7 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } ast::BiEq | ast::BiNe | ast::BiLt | ast::BiGe | ast::BiLe | ast::BiGt => { if is_simd { - base::compare_simd_types(bcx, lhs, rhs, intype, op.node, binop_debug_loc) + base::compare_simd_types(bcx, lhs, rhs, intype, val_ty(lhs), op.node, binop_debug_loc) } else { base::compare_scalar_types(bcx, lhs, rhs, intype, op.node, binop_debug_loc) } diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 225ff52a63c59..b316d105d0cdf 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -34,7 +34,7 @@ use middle::subst::Substs; use std::cmp; use libc::c_uint; use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi}; -use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System}; +use syntax::abi::{PlatformIntrinsic, RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System}; use syntax::codemap::Span; use syntax::parse::token::{InternedString, special_idents}; use syntax::ast; @@ -81,6 +81,10 @@ pub fn llvm_calling_convention(ccx: &CrateContext, // Intrinsics are emitted at the call site ccx.sess().bug("asked to register intrinsic fn"); } + PlatformIntrinsic => { + // Intrinsics are emitted at the call site + ccx.sess().bug("asked to register platform intrinsic fn"); + } Rust => { // FIXME(#3678) Implement linking to foreign fns with Rust ABI @@ -475,7 +479,7 @@ pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) { if let ast::ForeignItemFn(ref decl, _) = foreign_item.node { match foreign_mod.abi { - Rust | RustIntrinsic => {} + Rust | RustIntrinsic | PlatformIntrinsic => {} abi => { let ty = ccx.tcx().node_id_to_type(foreign_item.id); match ty.sty { @@ -612,7 +616,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // normal Rust function. This will be the type of the wrappee fn. match t.sty { ty::TyBareFn(_, ref f) => { - assert!(f.abi != Rust && f.abi != RustIntrinsic); + assert!(f.abi != Rust && f.abi != RustIntrinsic && f.abi != PlatformIntrinsic); } _ => { ccx.sess().bug(&format!("build_rust_fn: extern fn {} has ty {:?}, \ diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 33e5d814eb186..ded748e9894a0 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -11,6 +11,8 @@ #![allow(non_upper_case_globals)] use arena::TypedArena; +use intrinsics::{self, Intrinsic}; +use libc; use llvm; use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef, TypeKind}; use middle::subst; @@ -23,6 +25,7 @@ use trans::callee; use trans::cleanup; use trans::cleanup::CleanupMethods; use trans::common::*; +use trans::consts; use trans::datum::*; use trans::debuginfo::DebugLoc; use trans::declare; @@ -37,8 +40,11 @@ use middle::ty::{self, Ty, HasTypeFlags}; use middle::subst::Substs; use syntax::abi::{self, RustIntrinsic}; use syntax::ast; +use syntax::ptr::P; use syntax::parse::token; +use std::cmp::Ordering; + pub fn get_simple_intrinsic(ccx: &CrateContext, item: &ast::ForeignItem) -> Option { let name = match &*item.ident.name.as_str() { "sqrtf32" => "llvm.sqrt.f32", @@ -342,6 +348,13 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } } + // save the actual AST arguments for later (some places need to do + // const-evaluation on them) + let expr_arguments = match args { + callee::ArgExprs(args) => Some(args), + _ => None, + }; + // Push the arguments. let mut llargs = Vec::new(); bcx = callee::trans_args(bcx, @@ -800,7 +813,16 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, _ => C_null(llret_ty) } } - + (_, name) if name.starts_with("simd_") => { + generic_simd_intrinsic(bcx, name, + substs, + callee_ty, + expr_arguments, + &llargs, + ret_ty, llret_ty, + call_debug_location, + call_info) + } // This requires that atomic intrinsics follow a specific naming pattern: // "atomic_[_]", and no ordering means SeqCst (_, name) if name.starts_with("atomic_") => { @@ -897,7 +919,40 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } - (_, _) => ccx.sess().span_bug(foreign_item.span, "unknown intrinsic") + (_, _) => { + let intr = match Intrinsic::find(tcx, &name) { + Some(intr) => intr, + None => ccx.sess().span_bug(foreign_item.span, "unknown intrinsic"), + }; + fn ty_to_type(ccx: &CrateContext, t: &intrinsics::Type) -> Type { + use intrinsics::Type::*; + match *t { + Integer(x) => Type::ix(ccx, x as u64), + Float(x) => { + match x { + 32 => Type::f32(ccx), + 64 => Type::f64(ccx), + _ => unreachable!() + } + } + Pointer(_) => unimplemented!(), + Vector(ref t, length) => Type::vector(&ty_to_type(ccx, t), + length as u64) + } + } + + let inputs = intr.inputs.iter().map(|t| ty_to_type(ccx, t)).collect::>(); + let outputs = ty_to_type(ccx, &intr.output); + match intr.definition { + intrinsics::IntrinsicDef::Named(name) => { + let f = declare::declare_cfn(ccx, + name, + Type::func(&inputs, &outputs), + tcx.mk_nil()); + Call(bcx, f, &llargs, None, call_debug_location) + } + } + } }; if val_ty(llval) != Type::void(ccx) && @@ -1263,3 +1318,261 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, *ccx.rust_try_fn().borrow_mut() = Some(rust_try); return rust_try } + +fn generic_simd_intrinsic<'blk, 'tcx, 'a> + (bcx: Block<'blk, 'tcx>, + name: &str, + substs: subst::Substs<'tcx>, + callee_ty: Ty<'tcx>, + args: Option<&[P]>, + llargs: &[ValueRef], + ret_ty: Ty<'tcx>, + llret_ty: Type, + call_debug_location: DebugLoc, + call_info: NodeIdAndSpan) -> ValueRef +{ + // macros for error handling: + macro_rules! emit_error { + ($msg: tt) => { + emit_error!($msg, ) + }; + ($msg: tt, $($fmt: tt)*) => { + bcx.sess().span_err(call_info.span, + &format!(concat!("invalid monomorphization of `{}` intrinsic: ", + $msg), + name, $($fmt)*)); + } + } + macro_rules! require { + ($cond: expr, $($fmt: tt)*) => { + if !$cond { + emit_error!($($fmt)*); + return C_null(llret_ty) + } + } + } + macro_rules! require_simd { + ($ty: expr, $position: expr) => { + require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty) + } + } + + + + let tcx = bcx.tcx(); + let arg_tys = match callee_ty.sty { + ty::TyBareFn(_, ref f) => { + bcx.tcx().erase_late_bound_regions(&f.sig.inputs()) + } + _ => unreachable!() + }; + + // every intrinsic takes a SIMD vector as its first argument + require_simd!(arg_tys[0], "input"); + let in_ty = arg_tys[0]; + let in_elem = arg_tys[0].simd_type(tcx); + let in_len = arg_tys[0].simd_size(tcx); + + let comparison = match name { + "simd_eq" => Some(ast::BiEq), + "simd_ne" => Some(ast::BiNe), + "simd_lt" => Some(ast::BiLt), + "simd_le" => Some(ast::BiLe), + "simd_gt" => Some(ast::BiGt), + "simd_ge" => Some(ast::BiGe), + _ => None + }; + + if let Some(cmp_op) = comparison { + require_simd!(ret_ty, "return"); + + let out_len = ret_ty.simd_size(tcx); + require!(in_len == out_len, + "expected return type with length {} (same as input type `{}`), \ + found `{}` with length {}", + in_len, in_ty, + ret_ty, out_len); + require!(llret_ty.element_type().kind() == llvm::Integer, + "expected return type with integer elements, found `{}` with non-integer `{}`", + ret_ty, + ret_ty.simd_type(tcx)); + + return compare_simd_types(bcx, + llargs[0], + llargs[1], + in_elem, + llret_ty, + cmp_op, + call_debug_location) + } + + if name.starts_with("simd_shuffle") { + let n: usize = match name["simd_shuffle".len()..].parse() { + Ok(n) => n, + Err(_) => tcx.sess.span_bug(call_info.span, + "bad `simd_shuffle` instruction only caught in trans?") + }; + + require_simd!(ret_ty, "return"); + + let out_len = ret_ty.simd_size(tcx); + require!(out_len == n, + "expected return type of length {}, found `{}` with length {}", + n, ret_ty, out_len); + require!(in_elem == ret_ty.simd_type(tcx), + "expected return element type `{}` (element of input `{}`), \ + found `{}` with element type `{}`", + in_elem, in_ty, + ret_ty, ret_ty.simd_type(tcx)); + + let total_len = in_len as u64 * 2; + + let vector = match args { + Some(args) => &args[2], + None => bcx.sess().span_bug(call_info.span, + "intrinsic call with unexpected argument shape"), + }; + let vector = consts::const_expr(bcx.ccx(), vector, tcx.mk_substs(substs), None).0; + + let indices: Option> = (0..n) + .map(|i| { + let arg_idx = i; + let val = const_get_elt(bcx.ccx(), vector, &[i as libc::c_uint]); + let c = const_to_opt_uint(val); + match c { + None => { + emit_error!("shuffle index #{} is not a constant", arg_idx); + None + } + Some(idx) if idx >= total_len => { + emit_error!("shuffle index #{} is out of bounds (limit {})", + arg_idx, total_len); + None + } + Some(idx) => Some(C_i32(bcx.ccx(), idx as i32)), + } + }) + .collect(); + let indices = match indices { + Some(i) => i, + None => return C_null(llret_ty) + }; + + return ShuffleVector(bcx, llargs[0], llargs[1], C_vector(&indices)) + } + + if name == "simd_insert" { + require!(in_elem == arg_tys[2], + "expected inserted type `{}` (element of input `{}`), found `{}`", + in_elem, in_ty, arg_tys[2]); + return InsertElement(bcx, llargs[0], llargs[2], llargs[1]) + } + if name == "simd_extract" { + require!(ret_ty == in_elem, + "expected return type `{}` (element of input `{}`), found `{}`", + in_elem, in_ty, ret_ty); + return ExtractElement(bcx, llargs[0], llargs[1]) + } + + if name == "simd_cast" { + require_simd!(ret_ty, "return"); + let out_len = ret_ty.simd_size(tcx); + require!(in_len == out_len, + "expected return type with length {} (same as input type `{}`), \ + found `{}` with length {}", + in_len, in_ty, + ret_ty, out_len); + // casting cares about nominal type, not just structural type + let out_elem = ret_ty.simd_type(tcx); + + if in_elem == out_elem { return llargs[0]; } + + enum Style { Float, Int(/* is signed? */ bool), Unsupported } + + let (in_style, in_width) = match in_elem.sty { + // vectors of pointer-sized integers should've been + // disallowed before here, so this unwrap is safe. + ty::TyInt(i) => (Style::Int(true), i.bit_width().unwrap()), + ty::TyUint(u) => (Style::Int(false), u.bit_width().unwrap()), + ty::TyFloat(f) => (Style::Float, f.bit_width()), + _ => (Style::Unsupported, 0) + }; + let (out_style, out_width) = match out_elem.sty { + ty::TyInt(i) => (Style::Int(true), i.bit_width().unwrap()), + ty::TyUint(u) => (Style::Int(false), u.bit_width().unwrap()), + ty::TyFloat(f) => (Style::Float, f.bit_width()), + _ => (Style::Unsupported, 0) + }; + + match (in_style, out_style) { + (Style::Int(in_is_signed), Style::Int(_)) => { + return match in_width.cmp(&out_width) { + Ordering::Greater => Trunc(bcx, llargs[0], llret_ty), + Ordering::Equal => llargs[0], + Ordering::Less => if in_is_signed { + SExt(bcx, llargs[0], llret_ty) + } else { + ZExt(bcx, llargs[0], llret_ty) + } + } + } + (Style::Int(in_is_signed), Style::Float) => { + return if in_is_signed { + SIToFP(bcx, llargs[0], llret_ty) + } else { + UIToFP(bcx, llargs[0], llret_ty) + } + } + (Style::Float, Style::Int(out_is_signed)) => { + return if out_is_signed { + FPToSI(bcx, llargs[0], llret_ty) + } else { + FPToUI(bcx, llargs[0], llret_ty) + } + } + (Style::Float, Style::Float) => { + return match in_width.cmp(&out_width) { + Ordering::Greater => FPTrunc(bcx, llargs[0], llret_ty), + Ordering::Equal => llargs[0], + Ordering::Less => FPExt(bcx, llargs[0], llret_ty) + } + } + _ => {/* Unsupported. Fallthrough. */} + } + require!(false, + "unsupported cast from `{}` with element `{}` to `{}` with element `{}`", + in_ty, in_elem, + ret_ty, out_elem); + } + macro_rules! arith { + ($($name: ident: $($($p: ident),* => $call: expr),*;)*) => { + $( + if name == stringify!($name) { + match in_elem.sty { + $( + $(ty::$p(_))|* => { + return $call(bcx, llargs[0], llargs[1], call_debug_location) + } + )* + _ => {}, + } + require!(false, + "unsupported operation on `{}` with element `{}`", + in_ty, + in_elem) + })* + } + } + arith! { + simd_add: TyUint, TyInt => Add, TyFloat => FAdd; + simd_sub: TyUint, TyInt => Sub, TyFloat => FSub; + simd_mul: TyUint, TyInt => Mul, TyFloat => FMul; + simd_div: TyFloat => FDiv; + simd_shl: TyUint, TyInt => Shl; + simd_shr: TyUint => LShr, TyInt => AShr; + simd_and: TyUint, TyInt => And; + simd_or: TyUint, TyInt => Or; + simd_xor: TyUint, TyInt => Xor; + } + bcx.sess().span_bug(call_info.span, "unknown SIMD intrinsic"); +} diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index c2d1d19935a03..6527136b60294 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -90,7 +90,8 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }); if let ast_map::NodeForeignItem(_) = map_node { - if ccx.tcx().map.get_foreign_abi(fn_id.node) != abi::RustIntrinsic { + let abi = ccx.tcx().map.get_foreign_abi(fn_id.node); + if abi != abi::RustIntrinsic && abi != abi::PlatformIntrinsic { // Foreign externs don't have to be monomorphized. return (get_item_val(ccx, fn_id.node), mono_ty, true); } diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 5991d61a1e4ee..2e2f11bd133d8 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -182,6 +182,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ None => () } + debug!("sizing_type_of {:?}", t); let llsizingty = match t.sty { _ if !type_is_sized(cx.tcx(), t) => { Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false) @@ -223,7 +224,13 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ ty::TyStruct(..) => { if t.is_simd() { - let llet = type_of(cx, t.simd_type(cx.tcx())); + let e = t.simd_type(cx.tcx()); + if !e.is_machine() { + cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ + a non-machine element type `{}`", + t, e)) + } + let llet = type_of(cx, e); let n = t.simd_size(cx.tcx()) as u64; ensure_array_fits_in_address_space(cx, llet, n, t); Type::vector(&llet, n) @@ -240,6 +247,10 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ ty::TySlice(_) | ty::TyTrait(..) | ty::TyStr => unreachable!() }; + debug!("--> mapped t={:?} to llsizingty={}", + t, + cx.tn().type_to_string(llsizingty)); + cx.llsizingtypes().borrow_mut().insert(t, llsizingty); llsizingty } @@ -405,7 +416,13 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> } ty::TyStruct(def, ref substs) => { if t.is_simd() { - let llet = in_memory_type_of(cx, t.simd_type(cx.tcx())); + let e = t.simd_type(cx.tcx()); + if !e.is_machine() { + cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ + a non-machine element type `{}`", + t, e)) + } + let llet = in_memory_type_of(cx, e); let n = t.simd_size(cx.tcx()) as u64; ensure_array_fits_in_address_space(cx, llet, n, t); Type::vector(&llet, n) @@ -426,8 +443,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ty::TyError(..) => cx.sess().bug("type_of with TyError"), }; - debug!("--> mapped t={:?} {:?} to llty={}", - t, + debug!("--> mapped t={:?} to llty={}", t, cx.tn().type_to_string(llty)); diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs new file mode 100644 index 0000000000000..636f17db38c36 --- /dev/null +++ b/src/librustc_typeck/check/intrinsic.rs @@ -0,0 +1,509 @@ +// Copyright 2012-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. + +//! Type-checking for the rust-intrinsic and platform-intrinsic +//! intrinsics that the compiler exposes. + +use astconv::AstConv; +use intrinsics; +use middle::subst; +use middle::ty::FnSig; +use middle::ty::{self, Ty}; +use middle::ty_fold::TypeFolder; +use {CrateCtxt, require_same_types}; + +use std::collections::{HashMap}; +use syntax::abi; +use syntax::attr::AttrMetaMethods; +use syntax::ast; +use syntax::ast_util::local_def; +use syntax::codemap::Span; +use syntax::parse::token; + +fn equate_intrinsic_type<'a, 'tcx>(tcx: &ty::ctxt<'tcx>, it: &ast::ForeignItem, + n_tps: usize, + abi: abi::Abi, + inputs: Vec>, + output: ty::FnOutput<'tcx>) { + let fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { + unsafety: ast::Unsafety::Unsafe, + abi: abi, + sig: ty::Binder(FnSig { + inputs: inputs, + output: output, + variadic: false, + }), + })); + let i_ty = tcx.lookup_item_type(local_def(it.id)); + let i_n_tps = i_ty.generics.types.len(subst::FnSpace); + if i_n_tps != n_tps { + span_err!(tcx.sess, it.span, E0094, + "intrinsic has wrong number of type \ + parameters: found {}, expected {}", + i_n_tps, n_tps); + } else { + require_same_types(tcx, + None, + false, + it.span, + i_ty.ty, + fty, + || { + format!("intrinsic has wrong type: expected `{}`", + fty) + }); + } +} + +/// Remember to add all intrinsics here, in librustc_trans/trans/intrinsic.rs, +/// and in libcore/intrinsics.rs +pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { + fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> { + let name = token::intern(&format!("P{}", n)); + ccx.tcx.mk_param(subst::FnSpace, n, name) + } + + let tcx = ccx.tcx; + let name = it.ident.name.as_str(); + let (n_tps, inputs, output) = if name.starts_with("atomic_") { + let split : Vec<&str> = name.split('_').collect(); + assert!(split.len() >= 2, "Atomic intrinsic not correct format"); + + //We only care about the operation here + let (n_tps, inputs, output) = match split[1] { + "cxchg" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)), + param(ccx, 0), + param(ccx, 0)), + param(ccx, 0)), + "load" => (1, vec!(tcx.mk_imm_ptr(param(ccx, 0))), + param(ccx, 0)), + "store" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)), + tcx.mk_nil()), + + "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" | + "min" | "umax" | "umin" => { + (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)), + param(ccx, 0)) + } + "fence" | "singlethreadfence" => { + (0, Vec::new(), tcx.mk_nil()) + } + op => { + span_err!(tcx.sess, it.span, E0092, + "unrecognized atomic operation function: `{}`", op); + return; + } + }; + (n_tps, inputs, ty::FnConverging(output)) + } else if &name[..] == "abort" || &name[..] == "unreachable" { + (0, Vec::new(), ty::FnDiverging) + } else { + let (n_tps, inputs, output) = match &name[..] { + "breakpoint" => (0, Vec::new(), tcx.mk_nil()), + "size_of" | + "pref_align_of" | "min_align_of" => (1, Vec::new(), ccx.tcx.types.usize), + "size_of_val" | "min_align_of_val" => { + (1, vec![ + tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), + ty::BrAnon(0))), + param(ccx, 0)) + ], ccx.tcx.types.usize) + } + "init" | "init_dropped" => (1, Vec::new(), param(ccx, 0)), + "uninit" => (1, Vec::new(), param(ccx, 0)), + "forget" => (1, vec!( param(ccx, 0) ), tcx.mk_nil()), + "transmute" => (2, vec!( param(ccx, 0) ), param(ccx, 1)), + "move_val_init" => { + (1, + vec!( + tcx.mk_mut_ptr(param(ccx, 0)), + param(ccx, 0) + ), + tcx.mk_nil()) + } + "drop_in_place" => { + (1, vec![tcx.mk_mut_ptr(param(ccx, 0))], tcx.mk_nil()) + } + "needs_drop" => (1, Vec::new(), ccx.tcx.types.bool), + + "type_name" => (1, Vec::new(), tcx.mk_static_str()), + "type_id" => (1, Vec::new(), ccx.tcx.types.u64), + "offset" | "arith_offset" => { + (1, + vec!( + tcx.mk_ptr(ty::TypeAndMut { + ty: param(ccx, 0), + mutbl: ast::MutImmutable + }), + ccx.tcx.types.isize + ), + tcx.mk_ptr(ty::TypeAndMut { + ty: param(ccx, 0), + mutbl: ast::MutImmutable + })) + } + "copy" | "copy_nonoverlapping" => { + (1, + vec!( + tcx.mk_ptr(ty::TypeAndMut { + ty: param(ccx, 0), + mutbl: ast::MutImmutable + }), + tcx.mk_ptr(ty::TypeAndMut { + ty: param(ccx, 0), + mutbl: ast::MutMutable + }), + tcx.types.usize, + ), + tcx.mk_nil()) + } + "volatile_copy_memory" | "volatile_copy_nonoverlapping_memory" => { + (1, + vec!( + tcx.mk_ptr(ty::TypeAndMut { + ty: param(ccx, 0), + mutbl: ast::MutMutable + }), + tcx.mk_ptr(ty::TypeAndMut { + ty: param(ccx, 0), + mutbl: ast::MutImmutable + }), + tcx.types.usize, + ), + tcx.mk_nil()) + } + "write_bytes" | "volatile_set_memory" => { + (1, + vec!( + tcx.mk_ptr(ty::TypeAndMut { + ty: param(ccx, 0), + mutbl: ast::MutMutable + }), + tcx.types.u8, + tcx.types.usize, + ), + tcx.mk_nil()) + } + "sqrtf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "sqrtf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "powif32" => { + (0, + vec!( tcx.types.f32, tcx.types.i32 ), + tcx.types.f32) + } + "powif64" => { + (0, + vec!( tcx.types.f64, tcx.types.i32 ), + tcx.types.f64) + } + "sinf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "sinf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "cosf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "cosf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "powf32" => { + (0, + vec!( tcx.types.f32, tcx.types.f32 ), + tcx.types.f32) + } + "powf64" => { + (0, + vec!( tcx.types.f64, tcx.types.f64 ), + tcx.types.f64) + } + "expf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "expf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "exp2f32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "exp2f64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "logf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "logf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "log10f32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "log10f64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "log2f32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "log2f64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "fmaf32" => { + (0, + vec!( tcx.types.f32, tcx.types.f32, tcx.types.f32 ), + tcx.types.f32) + } + "fmaf64" => { + (0, + vec!( tcx.types.f64, tcx.types.f64, tcx.types.f64 ), + tcx.types.f64) + } + "fabsf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "fabsf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "copysignf32" => (0, vec!( tcx.types.f32, tcx.types.f32 ), tcx.types.f32), + "copysignf64" => (0, vec!( tcx.types.f64, tcx.types.f64 ), tcx.types.f64), + "floorf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "floorf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "ceilf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "ceilf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "truncf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "truncf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "rintf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "rintf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "nearbyintf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "nearbyintf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "roundf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "roundf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "ctpop8" => (0, vec!( tcx.types.u8 ), tcx.types.u8), + "ctpop16" => (0, vec!( tcx.types.u16 ), tcx.types.u16), + "ctpop32" => (0, vec!( tcx.types.u32 ), tcx.types.u32), + "ctpop64" => (0, vec!( tcx.types.u64 ), tcx.types.u64), + "ctlz8" => (0, vec!( tcx.types.u8 ), tcx.types.u8), + "ctlz16" => (0, vec!( tcx.types.u16 ), tcx.types.u16), + "ctlz32" => (0, vec!( tcx.types.u32 ), tcx.types.u32), + "ctlz64" => (0, vec!( tcx.types.u64 ), tcx.types.u64), + "cttz8" => (0, vec!( tcx.types.u8 ), tcx.types.u8), + "cttz16" => (0, vec!( tcx.types.u16 ), tcx.types.u16), + "cttz32" => (0, vec!( tcx.types.u32 ), tcx.types.u32), + "cttz64" => (0, vec!( tcx.types.u64 ), tcx.types.u64), + "bswap16" => (0, vec!( tcx.types.u16 ), tcx.types.u16), + "bswap32" => (0, vec!( tcx.types.u32 ), tcx.types.u32), + "bswap64" => (0, vec!( tcx.types.u64 ), tcx.types.u64), + + "volatile_load" => + (1, vec!( tcx.mk_imm_ptr(param(ccx, 0)) ), param(ccx, 0)), + "volatile_store" => + (1, vec!( tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0) ), tcx.mk_nil()), + + "i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" => + (0, vec!(tcx.types.i8, tcx.types.i8), + tcx.mk_tup(vec!(tcx.types.i8, tcx.types.bool))), + + "i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" => + (0, vec!(tcx.types.i16, tcx.types.i16), + tcx.mk_tup(vec!(tcx.types.i16, tcx.types.bool))), + + "i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" => + (0, vec!(tcx.types.i32, tcx.types.i32), + tcx.mk_tup(vec!(tcx.types.i32, tcx.types.bool))), + + "i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" => + (0, vec!(tcx.types.i64, tcx.types.i64), + tcx.mk_tup(vec!(tcx.types.i64, tcx.types.bool))), + + "u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" => + (0, vec!(tcx.types.u8, tcx.types.u8), + tcx.mk_tup(vec!(tcx.types.u8, tcx.types.bool))), + + "u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" => + (0, vec!(tcx.types.u16, tcx.types.u16), + tcx.mk_tup(vec!(tcx.types.u16, tcx.types.bool))), + + "u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=> + (0, vec!(tcx.types.u32, tcx.types.u32), + tcx.mk_tup(vec!(tcx.types.u32, tcx.types.bool))), + + "u64_add_with_overflow" | "u64_sub_with_overflow" | "u64_mul_with_overflow" => + (0, vec!(tcx.types.u64, tcx.types.u64), + tcx.mk_tup(vec!(tcx.types.u64, tcx.types.bool))), + + "unchecked_udiv" | "unchecked_sdiv" | "unchecked_urem" | "unchecked_srem" => + (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)), + + "overflowing_add" | "overflowing_sub" | "overflowing_mul" => + (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)), + + "return_address" => (0, vec![], tcx.mk_imm_ptr(tcx.types.u8)), + + "assume" => (0, vec![tcx.types.bool], tcx.mk_nil()), + + "discriminant_value" => (1, vec![ + tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), + ty::BrAnon(0))), + param(ccx, 0))], tcx.types.u64), + + "try" => { + let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8); + let fn_ty = ty::BareFnTy { + unsafety: ast::Unsafety::Normal, + abi: abi::Rust, + sig: ty::Binder(FnSig { + inputs: vec![mut_u8], + output: ty::FnOutput::FnConverging(tcx.mk_nil()), + variadic: false, + }), + }; + let fn_ty = tcx.mk_bare_fn(fn_ty); + (0, vec![tcx.mk_fn(None, fn_ty), mut_u8], mut_u8) + } + + ref other => { + span_err!(tcx.sess, it.span, E0093, + "unrecognized intrinsic function: `{}`", *other); + return; + } + }; + (n_tps, inputs, ty::FnConverging(output)) + }; + equate_intrinsic_type( + tcx, + it, + n_tps, + abi::RustIntrinsic, + inputs, + output + ) +} + +/// Type-check `extern "platform-intrinsic" { ... }` functions. +pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, + it: &ast::ForeignItem) { + let param = |n| { + let name = token::intern(&format!("P{}", n)); + ccx.tcx.mk_param(subst::FnSpace, n, name) + }; + + let tcx = ccx.tcx; + let i_ty = tcx.lookup_item_type(local_def(it.id)); + let i_n_tps = i_ty.generics.types.len(subst::FnSpace); + let name = it.ident.name.as_str(); + + let (n_tps, inputs, output) = match &*name { + "simd_eq" | "simd_ne" | "simd_lt" | "simd_le" | "simd_gt" | "simd_ge" => { + (2, vec![param(0), param(0)], param(1)) + } + "simd_add" | "simd_sub" | "simd_mul" | + "simd_div" | "simd_shl" | "simd_shr" | + "simd_and" | "simd_or" | "simd_xor" => { + (1, vec![param(0), param(0)], param(0)) + } + "simd_insert" => (2, vec![param(0), tcx.types.u32, param(1)], param(0)), + "simd_extract" => (2, vec![param(0), tcx.types.u32], param(1)), + "simd_cast" => (2, vec![param(0)], param(1)), + name if name.starts_with("simd_shuffle") => { + match name["simd_shuffle".len()..].parse() { + Ok(n) => { + let params = vec![param(0), param(0), + tcx.mk_ty(ty::TyArray(tcx.types.u32, n))]; + (2, params, param(1)) + } + Err(_) => { + span_err!(tcx.sess, it.span, E0439, + "invalid `simd_shuffle`, needs length: `{}`", name); + return + } + } + } + _ => { + match intrinsics::Intrinsic::find(tcx, &name) { + Some(intr) => { + // this function is a platform specific intrinsic + if i_n_tps != 0 { + span_err!(tcx.sess, it.span, E0440, + "platform-specific intrinsic has wrong number of type \ + parameters: found {}, expected 0", + i_n_tps); + return + } + + let mut structural_to_nomimal = HashMap::new(); + + let sig = tcx.no_late_bound_regions(i_ty.ty.fn_sig()).unwrap(); + let input_pairs = intr.inputs.iter().zip(&sig.inputs); + for (i, (expected_arg, arg)) in input_pairs.enumerate() { + match_intrinsic_type_to_type(tcx, &format!("argument {}", i + 1), it.span, + &mut structural_to_nomimal, expected_arg, arg); + } + match_intrinsic_type_to_type(tcx, "return value", it.span, + &mut structural_to_nomimal, + &intr.output, sig.output.unwrap()); + return + } + None => { + span_err!(tcx.sess, it.span, E0441, + "unrecognized platform-specific intrinsic function: `{}`", name); + return; + } + } + } + }; + + equate_intrinsic_type( + tcx, + it, + n_tps, + abi::PlatformIntrinsic, + inputs, + ty::FnConverging(output) + ) +} + +// walk the expected type and the actual type in lock step, checking they're +// the same, in a kinda-structural way, i.e. `Vector`s have to be simd structs with +// exactly the right element type +fn match_intrinsic_type_to_type<'tcx, 'a>( + tcx: &ty::ctxt<'tcx>, + position: &str, + span: Span, + structural_to_nominal: &mut HashMap<&'a intrinsics::Type, ty::Ty<'tcx>>, + expected: &'a intrinsics::Type, t: ty::Ty<'tcx>) +{ + use intrinsics::Type::*; + + let simple_error = |real: &str, expected: &str| { + span_err!(tcx.sess, span, E0442, + "intrinsic {} has wrong type: found {}, expected {}", + position, real, expected) + }; + + match *expected { + Integer(bits) => match (bits, &t.sty) { + (8, &ty::TyInt(ast::TyI8)) | (8, &ty::TyUint(ast::TyU8)) | + (16, &ty::TyInt(ast::TyI16)) | (16, &ty::TyUint(ast::TyU16)) | + (32, &ty::TyInt(ast::TyI32)) | (32, &ty::TyUint(ast::TyU32)) | + (64, &ty::TyInt(ast::TyI64)) | (64, &ty::TyUint(ast::TyU64)) => {}, + _ => simple_error(&format!("`{}`", t), + &format!("`i{n}` or `u{n}`", n = bits)), + }, + Float(bits) => match (bits, &t.sty) { + (32, &ty::TyFloat(ast::TyF32)) | + (64, &ty::TyFloat(ast::TyF64)) => {}, + _ => simple_error(&format!("`{}`", t), + &format!("`f{n}`", n = bits)), + }, + Pointer(_) => unimplemented!(), + Vector(ref inner_expected, len) => { + if !t.is_simd() { + simple_error(&format!("non-simd type `{}`", t), + "simd type"); + return; + } + let t_len = t.simd_size(tcx); + if len as usize != t_len { + simple_error(&format!("vector with length {}", t_len), + &format!("length {}", len)); + return; + } + let t_ty = t.simd_type(tcx); + { + // check that a given structural type always has the same an intrinsic definition + let previous = structural_to_nominal.entry(expected).or_insert(t); + if *previous != t { + // this gets its own error code because it is non-trivial + span_err!(tcx.sess, span, E0443, + "intrinsic {} has wrong type: found `{}`, expected `{}` which \ + was used for this vector type previously in this signature", + position, + t, + *previous); + return; + } + } + match_intrinsic_type_to_type(tcx, + position, + span, + structural_to_nominal, + inner_expected, + t_ty) + } + } +} diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index be008d522858c..aaa0111cae098 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -101,7 +101,7 @@ use middle::ty_fold::{TypeFolder, TypeFoldable}; use require_c_abi_if_variadic; use rscope::{ElisionFailureInfo, RegionScope}; use session::Session; -use {CrateCtxt, lookup_full_def, require_same_types}; +use {CrateCtxt, lookup_full_def}; use TypeAndSubsts; use lint; use util::common::{block_query, ErrorReported, indenter, loop_query}; @@ -109,7 +109,7 @@ use util::nodemap::{DefIdMap, FnvHashMap, NodeMap}; use util::lev_distance::lev_distance; use std::cell::{Cell, Ref, RefCell}; -use std::collections::HashSet; +use std::collections::{HashSet}; use std::mem::replace; use std::slice; use syntax::{self, abi, attr}; @@ -139,6 +139,7 @@ mod cast; mod closure; mod callee; mod compare_method; +mod intrinsic; mod op; /// closures defined within the function. For example: @@ -716,7 +717,11 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { ast::ItemForeignMod(ref m) => { if m.abi == abi::RustIntrinsic { for item in &m.items { - check_intrinsic_type(ccx, &**item); + intrinsic::check_intrinsic_type(ccx, &**item); + } + } else if m.abi == abi::PlatformIntrinsic { + for item in &m.items { + intrinsic::check_platform_intrinsic_type(ccx, &**item); } } else { for item in &m.items { @@ -4212,10 +4217,6 @@ pub fn check_instantiable(tcx: &ty::ctxt, pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) { let t = tcx.node_id_to_type(id); - if t.needs_subst() { - span_err!(tcx.sess, sp, E0074, "SIMD vector cannot be generic"); - return; - } match t.sty { ty::TyStruct(def, substs) => { let fields = &def.struct_variant().fields; @@ -4228,10 +4229,14 @@ pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) { span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous"); return; } - if !e.is_machine() { - span_err!(tcx.sess, sp, E0077, - "SIMD vector element type should be machine type"); - return; + match e.sty { + ty::TyParam(_) => { /* struct(T, T, T, T) is ok */ } + _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ } + _ => { + span_err!(tcx.sess, sp, E0077, + "SIMD vector element type should be machine type"); + return; + } } } _ => () @@ -4317,6 +4322,9 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, "discriminant type specified here"); } } + attr::ReprSimd => { + ccx.tcx.sess.bug("range_to_inttype: found ReprSimd on an enum"); + } attr::ReprPacked => { ccx.tcx.sess.bug("range_to_inttype: found ReprPacked on an enum"); } @@ -4976,315 +4984,3 @@ pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } } - -/// Remember to add all intrinsics here, in librustc_trans/trans/intrinsic.rs, -/// and in libcore/intrinsics.rs -pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { - fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> { - let name = token::intern(&format!("P{}", n)); - ccx.tcx.mk_param(subst::FnSpace, n, name) - } - - let tcx = ccx.tcx; - let name = it.ident.name.as_str(); - let (n_tps, inputs, output) = if name.starts_with("atomic_") { - let split : Vec<&str> = name.split('_').collect(); - assert!(split.len() >= 2, "Atomic intrinsic not correct format"); - - //We only care about the operation here - let (n_tps, inputs, output) = match split[1] { - "cxchg" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)), - param(ccx, 0), - param(ccx, 0)), - param(ccx, 0)), - "load" => (1, vec!(tcx.mk_imm_ptr(param(ccx, 0))), - param(ccx, 0)), - "store" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)), - tcx.mk_nil()), - - "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" | - "min" | "umax" | "umin" => { - (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)), - param(ccx, 0)) - } - "fence" | "singlethreadfence" => { - (0, Vec::new(), tcx.mk_nil()) - } - op => { - span_err!(tcx.sess, it.span, E0092, - "unrecognized atomic operation function: `{}`", op); - return; - } - }; - (n_tps, inputs, ty::FnConverging(output)) - } else if &name[..] == "abort" || &name[..] == "unreachable" { - (0, Vec::new(), ty::FnDiverging) - } else { - let (n_tps, inputs, output) = match &name[..] { - "breakpoint" => (0, Vec::new(), tcx.mk_nil()), - "size_of" | - "pref_align_of" | "min_align_of" => (1, Vec::new(), ccx.tcx.types.usize), - "size_of_val" | "min_align_of_val" => { - (1, vec![ - tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), - ty::BrAnon(0))), - param(ccx, 0)) - ], ccx.tcx.types.usize) - } - "init" | "init_dropped" => (1, Vec::new(), param(ccx, 0)), - "uninit" => (1, Vec::new(), param(ccx, 0)), - "forget" => (1, vec!( param(ccx, 0) ), tcx.mk_nil()), - "transmute" => (2, vec!( param(ccx, 0) ), param(ccx, 1)), - "move_val_init" => { - (1, - vec!( - tcx.mk_mut_ptr(param(ccx, 0)), - param(ccx, 0) - ), - tcx.mk_nil()) - } - "drop_in_place" => { - (1, vec![tcx.mk_mut_ptr(param(ccx, 0))], tcx.mk_nil()) - } - "needs_drop" => (1, Vec::new(), ccx.tcx.types.bool), - - "type_name" => (1, Vec::new(), tcx.mk_static_str()), - "type_id" => (1, Vec::new(), ccx.tcx.types.u64), - "offset" | "arith_offset" => { - (1, - vec!( - tcx.mk_ptr(ty::TypeAndMut { - ty: param(ccx, 0), - mutbl: ast::MutImmutable - }), - ccx.tcx.types.isize - ), - tcx.mk_ptr(ty::TypeAndMut { - ty: param(ccx, 0), - mutbl: ast::MutImmutable - })) - } - "copy" | "copy_nonoverlapping" => { - (1, - vec!( - tcx.mk_ptr(ty::TypeAndMut { - ty: param(ccx, 0), - mutbl: ast::MutImmutable - }), - tcx.mk_ptr(ty::TypeAndMut { - ty: param(ccx, 0), - mutbl: ast::MutMutable - }), - tcx.types.usize, - ), - tcx.mk_nil()) - } - "volatile_copy_memory" | "volatile_copy_nonoverlapping_memory" => { - (1, - vec!( - tcx.mk_ptr(ty::TypeAndMut { - ty: param(ccx, 0), - mutbl: ast::MutMutable - }), - tcx.mk_ptr(ty::TypeAndMut { - ty: param(ccx, 0), - mutbl: ast::MutImmutable - }), - tcx.types.usize, - ), - tcx.mk_nil()) - } - "write_bytes" | "volatile_set_memory" => { - (1, - vec!( - tcx.mk_ptr(ty::TypeAndMut { - ty: param(ccx, 0), - mutbl: ast::MutMutable - }), - tcx.types.u8, - tcx.types.usize, - ), - tcx.mk_nil()) - } - "sqrtf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "sqrtf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "powif32" => { - (0, - vec!( tcx.types.f32, tcx.types.i32 ), - tcx.types.f32) - } - "powif64" => { - (0, - vec!( tcx.types.f64, tcx.types.i32 ), - tcx.types.f64) - } - "sinf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "sinf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "cosf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "cosf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "powf32" => { - (0, - vec!( tcx.types.f32, tcx.types.f32 ), - tcx.types.f32) - } - "powf64" => { - (0, - vec!( tcx.types.f64, tcx.types.f64 ), - tcx.types.f64) - } - "expf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "expf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "exp2f32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "exp2f64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "logf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "logf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "log10f32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "log10f64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "log2f32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "log2f64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "fmaf32" => { - (0, - vec!( tcx.types.f32, tcx.types.f32, tcx.types.f32 ), - tcx.types.f32) - } - "fmaf64" => { - (0, - vec!( tcx.types.f64, tcx.types.f64, tcx.types.f64 ), - tcx.types.f64) - } - "fabsf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "fabsf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "copysignf32" => (0, vec!( tcx.types.f32, tcx.types.f32 ), tcx.types.f32), - "copysignf64" => (0, vec!( tcx.types.f64, tcx.types.f64 ), tcx.types.f64), - "floorf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "floorf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "ceilf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "ceilf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "truncf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "truncf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "rintf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "rintf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "nearbyintf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "nearbyintf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "roundf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "roundf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "ctpop8" => (0, vec!( tcx.types.u8 ), tcx.types.u8), - "ctpop16" => (0, vec!( tcx.types.u16 ), tcx.types.u16), - "ctpop32" => (0, vec!( tcx.types.u32 ), tcx.types.u32), - "ctpop64" => (0, vec!( tcx.types.u64 ), tcx.types.u64), - "ctlz8" => (0, vec!( tcx.types.u8 ), tcx.types.u8), - "ctlz16" => (0, vec!( tcx.types.u16 ), tcx.types.u16), - "ctlz32" => (0, vec!( tcx.types.u32 ), tcx.types.u32), - "ctlz64" => (0, vec!( tcx.types.u64 ), tcx.types.u64), - "cttz8" => (0, vec!( tcx.types.u8 ), tcx.types.u8), - "cttz16" => (0, vec!( tcx.types.u16 ), tcx.types.u16), - "cttz32" => (0, vec!( tcx.types.u32 ), tcx.types.u32), - "cttz64" => (0, vec!( tcx.types.u64 ), tcx.types.u64), - "bswap16" => (0, vec!( tcx.types.u16 ), tcx.types.u16), - "bswap32" => (0, vec!( tcx.types.u32 ), tcx.types.u32), - "bswap64" => (0, vec!( tcx.types.u64 ), tcx.types.u64), - - "volatile_load" => - (1, vec!( tcx.mk_imm_ptr(param(ccx, 0)) ), param(ccx, 0)), - "volatile_store" => - (1, vec!( tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0) ), tcx.mk_nil()), - - "i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" => - (0, vec!(tcx.types.i8, tcx.types.i8), - tcx.mk_tup(vec!(tcx.types.i8, tcx.types.bool))), - - "i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" => - (0, vec!(tcx.types.i16, tcx.types.i16), - tcx.mk_tup(vec!(tcx.types.i16, tcx.types.bool))), - - "i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" => - (0, vec!(tcx.types.i32, tcx.types.i32), - tcx.mk_tup(vec!(tcx.types.i32, tcx.types.bool))), - - "i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" => - (0, vec!(tcx.types.i64, tcx.types.i64), - tcx.mk_tup(vec!(tcx.types.i64, tcx.types.bool))), - - "u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" => - (0, vec!(tcx.types.u8, tcx.types.u8), - tcx.mk_tup(vec!(tcx.types.u8, tcx.types.bool))), - - "u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" => - (0, vec!(tcx.types.u16, tcx.types.u16), - tcx.mk_tup(vec!(tcx.types.u16, tcx.types.bool))), - - "u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=> - (0, vec!(tcx.types.u32, tcx.types.u32), - tcx.mk_tup(vec!(tcx.types.u32, tcx.types.bool))), - - "u64_add_with_overflow" | "u64_sub_with_overflow" | "u64_mul_with_overflow" => - (0, vec!(tcx.types.u64, tcx.types.u64), - tcx.mk_tup(vec!(tcx.types.u64, tcx.types.bool))), - - "unchecked_udiv" | "unchecked_sdiv" | "unchecked_urem" | "unchecked_srem" => - (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)), - - "overflowing_add" | "overflowing_sub" | "overflowing_mul" => - (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)), - - "return_address" => (0, vec![], tcx.mk_imm_ptr(tcx.types.u8)), - - "assume" => (0, vec![tcx.types.bool], tcx.mk_nil()), - - "discriminant_value" => (1, vec![ - tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), - ty::BrAnon(0))), - param(ccx, 0))], tcx.types.u64), - - "try" => { - let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8); - let fn_ty = ty::BareFnTy { - unsafety: ast::Unsafety::Normal, - abi: abi::Rust, - sig: ty::Binder(FnSig { - inputs: vec![mut_u8], - output: ty::FnOutput::FnConverging(tcx.mk_nil()), - variadic: false, - }), - }; - let fn_ty = tcx.mk_bare_fn(fn_ty); - (0, vec![tcx.mk_fn(None, fn_ty), mut_u8], mut_u8) - } - - ref other => { - span_err!(tcx.sess, it.span, E0093, - "unrecognized intrinsic function: `{}`", *other); - return; - } - }; - (n_tps, inputs, ty::FnConverging(output)) - }; - let fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { - unsafety: ast::Unsafety::Unsafe, - abi: abi::RustIntrinsic, - sig: ty::Binder(FnSig { - inputs: inputs, - output: output, - variadic: false, - }), - })); - let i_ty = ccx.tcx.lookup_item_type(local_def(it.id)); - let i_n_tps = i_ty.generics.types.len(subst::FnSpace); - if i_n_tps != n_tps { - span_err!(tcx.sess, it.span, E0094, - "intrinsic has wrong number of type \ - parameters: found {}, expected {}", - i_n_tps, n_tps); - } else { - require_same_types(tcx, - None, - false, - it.span, - i_ty.ty, - fty, - || { - format!("intrinsic has wrong type: expected `{}`", - fty) - }); - } -} diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index b139cb45bf207..59856a4a9c639 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -82,18 +82,6 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, check_expr(fcx, lhs_expr); let lhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr)); - // Annoyingly, SIMD ops don't fit into the PartialEq/PartialOrd - // traits, because their return type is not bool. Perhaps this - // should change, but for now if LHS is SIMD we go down a - // different path that bypassess all traits. - if lhs_ty.is_simd() { - check_expr_coercable_to_type(fcx, rhs_expr, lhs_ty); - let rhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr)); - let return_ty = enforce_builtin_binop_types(fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); - fcx.write_ty(expr.id, return_ty); - return; - } - match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => { // && and || are a simple case. @@ -154,12 +142,6 @@ fn enforce_builtin_binop_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } BinOpCategory::Shift => { - // For integers, the shift amount can be of any integral - // type. For simd, the type must match exactly. - if lhs_ty.is_simd() { - demand::suptype(fcx, rhs_expr.span, lhs_ty, rhs_ty); - } - // result type is same as LHS always lhs_ty } @@ -174,27 +156,7 @@ fn enforce_builtin_binop_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, BinOpCategory::Comparison => { // both LHS and RHS and result will have the same type demand::suptype(fcx, rhs_expr.span, lhs_ty, rhs_ty); - - // if this is simd, result is same as lhs, else bool - if lhs_ty.is_simd() { - let unit_ty = lhs_ty.simd_type(tcx); - debug!("enforce_builtin_binop_types: lhs_ty={:?} unit_ty={:?}", - lhs_ty, - unit_ty); - if !unit_ty.is_integral() { - tcx.sess.span_err( - lhs_expr.span, - &format!("binary comparison operation `{}` not supported \ - for floating point SIMD vector `{}`", - ast_util::binop_to_string(op.node), - lhs_ty)); - tcx.types.err - } else { - lhs_ty - } - } else { - tcx.mk_bool() - } + tcx.mk_bool() } } } @@ -427,29 +389,25 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, BinOpCategory::Shift => { lhs.references_error() || rhs.references_error() || - lhs.is_integral() && rhs.is_integral() || - lhs.is_simd() && rhs.is_simd() + lhs.is_integral() && rhs.is_integral() } BinOpCategory::Math => { lhs.references_error() || rhs.references_error() || lhs.is_integral() && rhs.is_integral() || - lhs.is_floating_point() && rhs.is_floating_point() || - lhs.is_simd() && rhs.is_simd() + lhs.is_floating_point() && rhs.is_floating_point() } BinOpCategory::Bitwise => { lhs.references_error() || rhs.references_error() || lhs.is_integral() && rhs.is_integral() || lhs.is_floating_point() && rhs.is_floating_point() || - lhs.is_simd() && rhs.is_simd() || lhs.is_bool() && rhs.is_bool() } BinOpCategory::Comparison => { lhs.references_error() || rhs.references_error() || - lhs.is_scalar() && rhs.is_scalar() || - lhs.is_simd() && rhs.is_simd() + lhs.is_scalar() && rhs.is_scalar() } } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 7d3fea7813c23..b0f07c14bc900 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -2772,5 +2772,11 @@ register_diagnostics! { // type because its default value `{}` references the type `Self`" E0399, // trait items need to be implemented because the associated // type `{}` was overridden - E0436 // functional record update requires a struct + E0436, // functional record update requires a struct + E0439, // invalid `simd_shuffle`, needs length: `{}` + E0440, // platform-specific intrinsic has wrong number of type parameters + E0441, // unrecognized platform-specific intrinsic function + E0442, // intrinsic {} has wrong type: found {}, expected {} + E0443, // intrinsic {} has wrong type: found `{}`, expected `{}` which + // was used for this vector type previously in this signature } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 08fd4d8dee5d5..82a605cd14fa4 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -96,6 +96,7 @@ This API is completely unstable and subject to change. extern crate arena; extern crate fmt_macros; extern crate rustc; +extern crate rustc_platform_intrinsics as intrinsics; pub use rustc::lint; pub use rustc::metadata; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index ba9caa2f3f356..81399938f27c5 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -10,7 +10,7 @@ pub use self::MaybeTyped::*; use rustc_lint; -use rustc_driver::driver; +use rustc_driver::{driver, target_features}; use rustc::session::{self, config}; use rustc::middle::{privacy, ty}; use rustc::ast_map; @@ -119,7 +119,8 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: Externs, span_diagnostic_handler); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - let cfg = config::build_configuration(&sess); + let mut cfg = config::build_configuration(&sess); + target_features::add_configuration(&mut cfg, &sess); let krate = driver::phase_1_parse_input(&sess, cfg, &input); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 655fa04c2644e..bc7252fa33a86 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -294,6 +294,7 @@ pub use core::mem; pub use core::ops; pub use core::ptr; pub use core::raw; +#[allow(deprecated)] pub use core::simd; pub use core::result; pub use core::option; diff --git a/src/libstd/rt/unwind/seh64_gnu.rs b/src/libstd/rt/unwind/seh64_gnu.rs index 847ba47ff7251..78f969bfbeb5b 100644 --- a/src/libstd/rt/unwind/seh64_gnu.rs +++ b/src/libstd/rt/unwind/seh64_gnu.rs @@ -21,7 +21,6 @@ use self::EXCEPTION_DISPOSITION::*; use rt::dwarf::eh; use core::mem; use core::ptr; -use simd; use libc::{c_void, c_ulonglong, DWORD, LPVOID}; type ULONG_PTR = c_ulonglong; diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index 7078ee92085fb..d36ca709c5c94 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -194,6 +194,8 @@ mod arch { #[cfg(target_arch = "x86_64")] mod arch { + #![allow(deprecated)] + use libc::{c_longlong, c_ulonglong}; use libc::types::os::arch::extra::{WORD, DWORD, DWORDLONG}; use simd; diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 50c86a80b4ab5..c0fe541ead510 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -47,6 +47,7 @@ pub enum Abi { System, RustIntrinsic, RustCall, + PlatformIntrinsic, } #[allow(non_camel_case_types)] @@ -95,6 +96,7 @@ const AbiDatas: &'static [AbiData] = &[ AbiData {abi: System, name: "system" }, AbiData {abi: RustIntrinsic, name: "rust-intrinsic" }, AbiData {abi: RustCall, name: "rust-call" }, + AbiData {abi: PlatformIntrinsic, name: "platform-intrinsic" } ]; /// Returns the ABI with the given name (if any). diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 0bcd97cfe873f..2d72c8fe2a48c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1339,6 +1339,15 @@ impl IntTy { TyI16 | TyI32 | TyI64 => 3, } } + pub fn bit_width(&self) -> Option { + Some(match *self { + TyIs => return None, + TyI8 => 8, + TyI16 => 16, + TyI32 => 32, + TyI64 => 64, + }) + } } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] @@ -1357,6 +1366,15 @@ impl UintTy { TyU16 | TyU32 | TyU64 => 3, } } + pub fn bit_width(&self) -> Option { + Some(match *self { + TyUs => return None, + TyU8 => 8, + TyU16 => 16, + TyU32 => 32, + TyU64 => 64, + }) + } } impl fmt::Debug for UintTy { @@ -1395,6 +1413,12 @@ impl FloatTy { TyF32 | TyF64 => 3, // add F128 handling here } } + pub fn bit_width(&self) -> usize { + match *self { + TyF32 => 32, + TyF64 => 64, + } + } } // Bind a type to an associated type: `A=Foo`. diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 5e16465b4d4bf..7540c2ff831e9 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -19,6 +19,7 @@ use ast::{AttrId, Attribute, Attribute_, MetaItem, MetaWord, MetaNameValue, Meta use codemap::{Span, Spanned, spanned, dummy_spanned}; use codemap::BytePos; use diagnostic::SpanHandler; +use feature_gate::GatedCfg; use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use parse::token::{InternedString, intern_and_get_ident}; use parse::token; @@ -357,24 +358,28 @@ pub fn requests_inline(attrs: &[Attribute]) -> bool { } /// Tests if a cfg-pattern matches the cfg set -pub fn cfg_matches(diagnostic: &SpanHandler, cfgs: &[P], cfg: &ast::MetaItem) -> bool { +pub fn cfg_matches(diagnostic: &SpanHandler, cfgs: &[P], cfg: &ast::MetaItem, + feature_gated_cfgs: &mut Vec) -> bool { match cfg.node { ast::MetaList(ref pred, ref mis) if &pred[..] == "any" => - mis.iter().any(|mi| cfg_matches(diagnostic, cfgs, &**mi)), + mis.iter().any(|mi| cfg_matches(diagnostic, cfgs, &**mi, feature_gated_cfgs)), ast::MetaList(ref pred, ref mis) if &pred[..] == "all" => - mis.iter().all(|mi| cfg_matches(diagnostic, cfgs, &**mi)), + mis.iter().all(|mi| cfg_matches(diagnostic, cfgs, &**mi, feature_gated_cfgs)), ast::MetaList(ref pred, ref mis) if &pred[..] == "not" => { if mis.len() != 1 { diagnostic.span_err(cfg.span, "expected 1 cfg-pattern"); return false; } - !cfg_matches(diagnostic, cfgs, &*mis[0]) + !cfg_matches(diagnostic, cfgs, &*mis[0], feature_gated_cfgs) } ast::MetaList(ref pred, _) => { diagnostic.span_err(cfg.span, &format!("invalid predicate `{}`", pred)); false }, - ast::MetaWord(_) | ast::MetaNameValue(..) => contains(cfgs, cfg), + ast::MetaWord(_) | ast::MetaNameValue(..) => { + feature_gated_cfgs.extend(GatedCfg::gate(cfg)); + contains(cfgs, cfg) + } } } @@ -579,6 +584,7 @@ pub fn find_repr_attrs(diagnostic: &SpanHandler, attr: &Attribute) -> Vec Some(ReprExtern), "packed" => Some(ReprPacked), + "simd" => Some(ReprSimd), _ => match int_type_of_word(&word) { Some(ity) => Some(ReprInt(item.span, ity)), None => { @@ -628,6 +634,7 @@ pub enum ReprAttr { ReprInt(Span, IntType), ReprExtern, ReprPacked, + ReprSimd, } impl ReprAttr { @@ -636,7 +643,8 @@ impl ReprAttr { ReprAny => false, ReprInt(_sp, ity) => ity.is_ffi_safe(), ReprExtern => true, - ReprPacked => false + ReprPacked => false, + ReprSimd => true, } } } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 366806bc19b49..faf0b51c8de0e 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -10,6 +10,7 @@ use attr::AttrMetaMethods; use diagnostic::SpanHandler; +use feature_gate::GatedCfg; use fold::Folder; use {ast, fold, attr}; use codemap::{Spanned, respan}; @@ -25,10 +26,13 @@ struct Context where F: FnMut(&[ast::Attribute]) -> bool { // Support conditional compilation by transforming the AST, stripping out // any items that do not belong in the current configuration -pub fn strip_unconfigured_items(diagnostic: &SpanHandler, krate: ast::Crate) -> ast::Crate { - let krate = process_cfg_attr(diagnostic, krate); +pub fn strip_unconfigured_items(diagnostic: &SpanHandler, krate: ast::Crate, + feature_gated_cfgs: &mut Vec) + -> ast::Crate +{ + let krate = process_cfg_attr(diagnostic, krate, feature_gated_cfgs); let config = krate.config.clone(); - strip_items(krate, |attrs| in_cfg(diagnostic, &config, attrs)) + strip_items(krate, |attrs| in_cfg(diagnostic, &config, attrs, feature_gated_cfgs)) } impl fold::Folder for Context where F: FnMut(&[ast::Attribute]) -> bool { @@ -248,7 +252,8 @@ fn foreign_item_in_cfg(cx: &mut Context, item: &ast::ForeignItem) -> bool // Determine if an item should be translated in the current crate // configuration based on the item's attributes -fn in_cfg(diagnostic: &SpanHandler, cfg: &[P], attrs: &[ast::Attribute]) -> bool { +fn in_cfg(diagnostic: &SpanHandler, cfg: &[P], attrs: &[ast::Attribute], + feature_gated_cfgs: &mut Vec) -> bool { attrs.iter().all(|attr| { let mis = match attr.node.value.node { ast::MetaList(_, ref mis) if attr.check_name("cfg") => mis, @@ -260,25 +265,29 @@ fn in_cfg(diagnostic: &SpanHandler, cfg: &[P], attrs: &[ast::Attr return true; } - attr::cfg_matches(diagnostic, cfg, &*mis[0]) + attr::cfg_matches(diagnostic, cfg, &*mis[0], + feature_gated_cfgs) }) } -struct CfgAttrFolder<'a> { +struct CfgAttrFolder<'a, 'b> { diag: &'a SpanHandler, config: ast::CrateConfig, + feature_gated_cfgs: &'b mut Vec } // Process `#[cfg_attr]`. -fn process_cfg_attr(diagnostic: &SpanHandler, krate: ast::Crate) -> ast::Crate { +fn process_cfg_attr(diagnostic: &SpanHandler, krate: ast::Crate, + feature_gated_cfgs: &mut Vec) -> ast::Crate { let mut fld = CfgAttrFolder { diag: diagnostic, config: krate.config.clone(), + feature_gated_cfgs: feature_gated_cfgs, }; fld.fold_crate(krate) } -impl<'a> fold::Folder for CfgAttrFolder<'a> { +impl<'a,'b> fold::Folder for CfgAttrFolder<'a,'b> { fn fold_attribute(&mut self, attr: ast::Attribute) -> Option { if !attr.check_name("cfg_attr") { return fold::noop_fold_attribute(attr, self); @@ -299,7 +308,8 @@ impl<'a> fold::Folder for CfgAttrFolder<'a> { } }; - if attr::cfg_matches(self.diag, &self.config[..], &cfg) { + if attr::cfg_matches(self.diag, &self.config[..], &cfg, + self.feature_gated_cfgs) { Some(respan(mi.span, ast::Attribute_ { id: attr::mk_attr_id(), style: attr.node.style, diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index d4b5e67eeb492..ef11a2bd66e80 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -17,6 +17,7 @@ use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION, CompilerExpansion}; use ext; use ext::expand; use ext::tt::macro_rules; +use feature_gate::GatedCfg; use parse; use parse::parser; use parse::token; @@ -632,6 +633,7 @@ pub struct ExtCtxt<'a> { pub backtrace: ExpnId, pub ecfg: expand::ExpansionConfig<'a>, pub crate_root: Option<&'static str>, + pub feature_gated_cfgs: &'a mut Vec, pub mod_path: Vec , pub exported_macros: Vec, @@ -642,7 +644,8 @@ pub struct ExtCtxt<'a> { impl<'a> ExtCtxt<'a> { pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig, - ecfg: expand::ExpansionConfig<'a>) -> ExtCtxt<'a> { + ecfg: expand::ExpansionConfig<'a>, + feature_gated_cfgs: &'a mut Vec) -> ExtCtxt<'a> { let env = initial_syntax_expander_table(&ecfg); ExtCtxt { parse_sess: parse_sess, @@ -651,6 +654,7 @@ impl<'a> ExtCtxt<'a> { mod_path: Vec::new(), ecfg: ecfg, crate_root: None, + feature_gated_cfgs: feature_gated_cfgs, exported_macros: Vec::new(), syntax_env: env, recursion_count: 0, diff --git a/src/libsyntax/ext/cfg.rs b/src/libsyntax/ext/cfg.rs index 8af7fb7b268af..aa654e30530af 100644 --- a/src/libsyntax/ext/cfg.rs +++ b/src/libsyntax/ext/cfg.rs @@ -34,6 +34,7 @@ pub fn expand_cfg<'cx>(cx: &mut ExtCtxt, return DummyResult::expr(sp); } - let matches_cfg = attr::cfg_matches(&cx.parse_sess.span_diagnostic, &cx.cfg, &*cfg); + let matches_cfg = attr::cfg_matches(&cx.parse_sess.span_diagnostic, &cx.cfg, &*cfg, + cx.feature_gated_cfgs); MacEager::expr(cx.expr_bool(sp, matches_cfg)) } diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 1f4860b7ec11e..f8f63e94ee574 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -739,7 +739,7 @@ fn find_repr_type_name(diagnostic: &SpanHandler, for a in type_attrs { for r in &attr::find_repr_attrs(diagnostic, a) { repr_type_name = match *r { - attr::ReprAny | attr::ReprPacked => continue, + attr::ReprAny | attr::ReprPacked | attr::ReprSimd => continue, attr::ReprExtern => "i32", attr::ReprInt(_, attr::SignedInt(ast::TyIs)) => "isize", diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index e61a0b5401efd..4f89b3494d403 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -21,7 +21,7 @@ use attr::AttrMetaMethods; use codemap; use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute, CompilerExpansion}; use ext::base::*; -use feature_gate::{self, Features}; +use feature_gate::{self, Features, GatedCfg}; use fold; use fold::*; use parse; @@ -1687,8 +1687,10 @@ pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess, // these are the macros being imported to this crate: imported_macros: Vec, user_exts: Vec, + feature_gated_cfgs: &mut Vec, c: Crate) -> Crate { - let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg); + let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg, + feature_gated_cfgs); if std_inject::no_core(&c) { cx.crate_root = None; } else if std_inject::no_std(&c) { @@ -1878,7 +1880,7 @@ mod tests { src, Vec::new(), &sess); // should fail: - expand_crate(&sess,test_ecfg(),vec!(),vec!(),crate_ast); + expand_crate(&sess,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast); } // make sure that macros can't escape modules @@ -1891,7 +1893,7 @@ mod tests { "".to_string(), src, Vec::new(), &sess); - expand_crate(&sess,test_ecfg(),vec!(),vec!(),crate_ast); + expand_crate(&sess,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast); } // macro_use modules should allow macros to escape @@ -1903,14 +1905,14 @@ mod tests { "".to_string(), src, Vec::new(), &sess); - expand_crate(&sess, test_ecfg(), vec!(), vec!(), crate_ast); + expand_crate(&sess, test_ecfg(), vec!(), vec!(), &mut vec![], crate_ast); } fn expand_crate_str(crate_str: String) -> ast::Crate { let ps = parse::ParseSess::new(); let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod()); // the cfg argument actually does matter, here... - expand_crate(&ps,test_ecfg(),vec!(),vec!(),crate_ast) + expand_crate(&ps,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast) } // find the pat_ident paths in a crate diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 694a1a43f593d..f5a0a2f4718b9 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -37,6 +37,7 @@ use visit::Visitor; use parse::token::{self, InternedString}; use std::ascii::AsciiExt; +use std::cmp; // If you change this list without updating src/doc/reference.md, @cmr will be sad // Don't ever remove anything from this list; set them to 'Removed'. @@ -177,6 +178,15 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ // Allows macros to appear in the type position. ("type_macros", "1.3.0", Active), + + // allow `repr(simd)`, and importing the various simd intrinsics + ("repr_simd", "1.4.0", Active), + + // Allows cfg(target_feature = "..."). + ("cfg_target_feature", "1.4.0", Active), + + // allow `extern "platform-intrinsic" { ... }` + ("platform_intrinsics", "1.4.0", Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -324,6 +334,59 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ ("recursion_limit", CrateLevel), ]; +macro_rules! cfg_fn { + (|$x: ident| $e: expr) => {{ + fn f($x: &Features) -> bool { + $e + } + f as fn(&Features) -> bool + }} +} +// cfg(...)'s that are feature gated +const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[ + // (name in cfg, feature, function to check if the feature is enabled) + ("target_feature", "cfg_target_feature", cfg_fn!(|x| x.cfg_target_feature)), +]; + +#[derive(Debug, Eq, PartialEq)] +pub struct GatedCfg { + span: Span, + index: usize, +} +impl Ord for GatedCfg { + fn cmp(&self, other: &GatedCfg) -> cmp::Ordering { + (self.span.lo.0, self.span.hi.0, self.index) + .cmp(&(other.span.lo.0, other.span.hi.0, other.index)) + } +} +impl PartialOrd for GatedCfg { + fn partial_cmp(&self, other: &GatedCfg) -> Option { + Some(self.cmp(other)) + } +} + +impl GatedCfg { + pub fn gate(cfg: &ast::MetaItem) -> Option { + let name = cfg.name(); + GATED_CFGS.iter() + .position(|info| info.0 == name) + .map(|idx| { + GatedCfg { + span: cfg.span, + index: idx + } + }) + } + pub fn check_and_emit(&self, diagnostic: &SpanHandler, features: &Features) { + let (cfg, feature, has_feature) = GATED_CFGS[self.index]; + if !has_feature(features) { + let explain = format!("`cfg({})` is experimental and subject to change", cfg); + emit_feature_err(diagnostic, feature, self.span, &explain); + } + } +} + + #[derive(PartialEq, Copy, Clone, Debug)] pub enum AttributeType { /// Normal, builtin attribute that is consumed @@ -369,6 +432,7 @@ pub struct Features { pub static_recursion: bool, pub default_type_parameter_fallback: bool, pub type_macros: bool, + pub cfg_target_feature: bool, } impl Features { @@ -396,6 +460,7 @@ impl Features { static_recursion: false, default_type_parameter_fallback: false, type_macros: false, + cfg_target_feature: false, } } } @@ -630,10 +695,16 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { across platforms, it is recommended to \ use `#[link(name = \"foo\")]` instead") } - if foreign_module.abi == Abi::RustIntrinsic { - self.gate_feature("intrinsics", - i.span, - "intrinsics are subject to change") + let maybe_feature = match foreign_module.abi { + Abi::RustIntrinsic => Some(("intrinsics", "intrinsics are subject to change")), + Abi::PlatformIntrinsic => { + Some(("platform_intrinsics", + "platform intrinsics are experimental and possibly buggy")) + } + _ => None + }; + if let Some((feature, msg)) = maybe_feature { + self.gate_feature(feature, i.span, msg) } } @@ -660,6 +731,20 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { if attr::contains_name(&i.attrs[..], "simd") { self.gate_feature("simd", i.span, "SIMD types are experimental and possibly buggy"); + self.context.span_handler.span_warn(i.span, + "the `#[simd]` attribute is deprecated, \ + use `#[repr(simd)]` instead"); + } + for attr in &i.attrs { + if attr.name() == "repr" { + for item in attr.meta_item_list().unwrap_or(&[]) { + if item.name() == "simd" { + self.gate_feature("repr_simd", i.span, + "SIMD types are experimental and possibly buggy"); + + } + } + } } } @@ -900,6 +985,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, static_recursion: cx.has_feature("static_recursion"), default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"), type_macros: cx.has_feature("type_macros"), + cfg_target_feature: cx.has_feature("cfg_target_feature"), } } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index ea99291d6c291..26fb287ce35d1 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -246,11 +246,13 @@ fn generate_test_harness(sess: &ParseSess, krate: ast::Crate, cfg: &ast::CrateConfig, sd: &diagnostic::SpanHandler) -> ast::Crate { + let mut feature_gated_cfgs = vec![]; let mut cx: TestCtxt = TestCtxt { sess: sess, span_diagnostic: sd, ext_cx: ExtCtxt::new(sess, cfg.clone(), - ExpansionConfig::default("test".to_string())), + ExpansionConfig::default("test".to_string()), + &mut feature_gated_cfgs), path: Vec::new(), testfns: Vec::new(), reexport_test_harness_main: reexport_test_harness_main, diff --git a/src/test/bench/shootout-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs index b359147702282..a6c77eaf7c630 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -91,7 +91,7 @@ fn mult(v: &[f64], out: &mut [f64], start: usize, a: F) for (j, chunk) in v.chunks(2).enumerate().map(|(j, s)| (2 * j, s)) { let top = f64x2(chunk[0], chunk[1]); let bot = f64x2(a(i, j), a(i, j + 1)); - sum += top / bot; + sum = sum + top / bot; } let f64x2(a, b) = sum; *slot = a + b; diff --git a/src/test/run-fail/overflowing-simd-rsh-1.rs b/src/test/compile-fail/feature-gate-cfg-target-feature.rs similarity index 55% rename from src/test/run-fail/overflowing-simd-rsh-1.rs rename to src/test/compile-fail/feature-gate-cfg-target-feature.rs index dffd627a0849f..7832e1c7c5152 100644 --- a/src/test/run-fail/overflowing-simd-rsh-1.rs +++ b/src/test/compile-fail/feature-gate-cfg-target-feature.rs @@ -8,16 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:thread '
' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions +#[cfg(target_feature = "x")] //~ ERROR `cfg(target_feature)` is experimental +#[cfg_attr(target_feature = "x", x)] //~ ERROR `cfg(target_feature)` is experimental +struct Foo(u64, u64); -#![feature(core_simd)] - -use std::simd::i32x4; - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } +#[cfg(not(any(all(target_feature = "x"))))] //~ ERROR `cfg(target_feature)` is experimental +fn foo() {} fn main() { - let _x = i32x4(-1, 0, 0, 0) >> id(i32x4(32, 0, 0, 0)); + cfg!(target_feature = "x"); + //~^ ERROR `cfg(target_feature)` is experimental and subject to change } diff --git a/src/test/compile-fail/gated-simd.rs b/src/test/compile-fail/feature-gate-repr-simd.rs similarity index 75% rename from src/test/compile-fail/gated-simd.rs rename to src/test/compile-fail/feature-gate-repr-simd.rs index 59c44bff3c79d..fdafb2ad950c9 100644 --- a/src/test/compile-fail/gated-simd.rs +++ b/src/test/compile-fail/feature-gate-repr-simd.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[simd] -pub struct i64x2(i64, i64); //~ ERROR: SIMD types are experimental +#[repr(simd)] +struct Foo(u64, u64); //~ error: SIMD types are experimental fn main() {} diff --git a/src/test/compile-fail/feature-gate-simd-ffi.rs b/src/test/compile-fail/feature-gate-simd-ffi.rs index 32c50b1b8c159..f7bd2fcbceb4f 100644 --- a/src/test/compile-fail/feature-gate-simd-ffi.rs +++ b/src/test/compile-fail/feature-gate-simd-ffi.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(simd, core_simd)] -#![allow(dead_code)] +#![feature(repr_simd, core_simd)] +#![allow(dead_code, deprecated)] use std::simd::f32x4; -#[simd] #[derive(Copy, Clone)] #[repr(C)] struct LocalSimd(u8, u8); +#[repr(simd)] #[derive(Copy, Clone)] #[repr(C)] struct LocalSimd(u8, u8); extern { fn foo() -> f32x4; //~ ERROR use of SIMD type diff --git a/src/test/compile-fail/simd-binop.rs b/src/test/compile-fail/simd-binop.rs deleted file mode 100644 index feffe5c0b06c8..0000000000000 --- a/src/test/compile-fail/simd-binop.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2014 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. - -// ignore-tidy-linelength - -#![feature(core)] - -use std::simd::f32x4; - -fn main() { - - let _ = f32x4(0.0, 0.0, 0.0, 0.0) == f32x4(0.0, 0.0, 0.0, 0.0); - //~^ ERROR binary comparison operation `==` not supported for floating point SIMD vector `core::simd::f32x4` - - let _ = f32x4(0.0, 0.0, 0.0, 0.0) != f32x4(0.0, 0.0, 0.0, 0.0); - //~^ ERROR binary comparison operation `!=` not supported for floating point SIMD vector `core::simd::f32x4` - - let _ = f32x4(0.0, 0.0, 0.0, 0.0) < f32x4(0.0, 0.0, 0.0, 0.0); - //~^ ERROR binary comparison operation `<` not supported for floating point SIMD vector `core::simd::f32x4` - - let _ = f32x4(0.0, 0.0, 0.0, 0.0) <= f32x4(0.0, 0.0, 0.0, 0.0); - //~^ ERROR binary comparison operation `<=` not supported for floating point SIMD vector `core::simd::f32x4` - - let _ = f32x4(0.0, 0.0, 0.0, 0.0) >= f32x4(0.0, 0.0, 0.0, 0.0); - //~^ ERROR binary comparison operation `>=` not supported for floating point SIMD vector `core::simd::f32x4` - - let _ = f32x4(0.0, 0.0, 0.0, 0.0) > f32x4(0.0, 0.0, 0.0, 0.0); - //~^ ERROR binary comparison operation `>` not supported for floating point SIMD vector `core::simd::f32x4` - -} diff --git a/src/test/compile-fail/simd-intrinsic-declaration-type.rs b/src/test/compile-fail/simd-intrinsic-declaration-type.rs new file mode 100644 index 0000000000000..effa1ed04d8ec --- /dev/null +++ b/src/test/compile-fail/simd-intrinsic-declaration-type.rs @@ -0,0 +1,57 @@ +// 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(repr_simd, platform_intrinsics)] + +#[repr(simd)] +struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); +#[repr(simd)] +struct u16x8(u16, u16, u16, u16, u16, u16, u16, u16); + +#[repr(simd)] +struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, + i8, i8, i8, i8, i8, i8, i8, i8); +#[repr(simd)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +struct f32x4(f32, f32, f32, f32); +#[repr(simd)] +struct i64x2(i64, i64); + +// signed vs. unsigned doesn't matter +mod i { + use i16x8; + extern "platform-intrinsic" { + fn x86_mm_adds_epi16(x: i16x8, y: i16x8) -> i16x8; + } +} +mod u { + use u16x8; + extern "platform-intrinsic" { + fn x86_mm_adds_epi16(x: u16x8, y: u16x8) -> u16x8; + } +} +// but lengths do +extern "platform-intrinsic" { + fn x86_mm_adds_epi16(x: i8x16, y: i32x4) -> i64x2; + //~^ ERROR intrinsic argument 1 has wrong type + //~^^ ERROR intrinsic argument 2 has wrong type + //~^^^ ERROR intrinsic return value has wrong type +} +// and so does int vs. float +extern "platform-intrinsic" { + fn x86_mm_max_ps(x: i32x4, y: i32x4) -> i32x4; + //~^ ERROR intrinsic argument 1 has wrong type + //~^^ ERROR intrinsic argument 2 has wrong type + //~^^^ ERROR intrinsic return value has wrong type +} + + +fn main() {} diff --git a/src/test/compile-fail/simd-intrinsic-generic-arithmetic.rs b/src/test/compile-fail/simd-intrinsic-generic-arithmetic.rs new file mode 100644 index 0000000000000..35c368f4cbedb --- /dev/null +++ b/src/test/compile-fail/simd-intrinsic-generic-arithmetic.rs @@ -0,0 +1,102 @@ +// 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(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct i32x4(pub i32, pub i32, pub i32, pub i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_add(x: T, y: T) -> T; + fn simd_sub(x: T, y: T) -> T; + fn simd_mul(x: T, y: T) -> T; + fn simd_div(x: T, y: T) -> T; + fn simd_shl(x: T, y: T) -> T; + fn simd_shr(x: T, y: T) -> T; + fn simd_and(x: T, y: T) -> T; + fn simd_or(x: T, y: T) -> T; + fn simd_xor(x: T, y: T) -> T; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + let y = u32x4(0, 0, 0, 0); + let z = f32x4(0.0, 0.0, 0.0, 0.0); + + unsafe { + simd_add(x, x); + simd_add(y, y); + simd_add(z, z); + simd_sub(x, x); + simd_sub(y, y); + simd_sub(z, z); + simd_mul(x, x); + simd_mul(y, y); + simd_mul(z, z); + + simd_div(z, z); + + simd_shl(x, x); + simd_shl(y, y); + simd_shr(x, x); + simd_shr(y, y); + simd_and(x, x); + simd_and(y, y); + simd_or(x, x); + simd_or(y, y); + simd_xor(x, x); + simd_xor(y, y); + + + simd_add(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_sub(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_mul(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_div(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_shl(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_shr(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_and(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_or(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_xor(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + + + simd_div(x, x); +//~^ ERROR unsupported operation on `i32x4` with element `i32` + simd_div(y, y); +//~^ ERROR unsupported operation on `u32x4` with element `u32` + simd_shl(z, z); +//~^ ERROR unsupported operation on `f32x4` with element `f32` + simd_shr(z, z); +//~^ ERROR unsupported operation on `f32x4` with element `f32` + simd_and(z, z); +//~^ ERROR unsupported operation on `f32x4` with element `f32` + simd_or(z, z); +//~^ ERROR unsupported operation on `f32x4` with element `f32` + simd_xor(z, z); +//~^ ERROR unsupported operation on `f32x4` with element `f32` + } +} diff --git a/src/test/compile-fail/simd-intrinsic-generic-cast.rs b/src/test/compile-fail/simd-intrinsic-generic-cast.rs new file mode 100644 index 0000000000000..4999b790b130a --- /dev/null +++ b/src/test/compile-fail/simd-intrinsic-generic-cast.rs @@ -0,0 +1,51 @@ +// 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(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x8(i32, i32, i32, i32, + i32, i32, i32, i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x4(f32, f32, f32, f32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x8(f32, f32, f32, f32, + f32, f32, f32, f32); + + +extern "platform-intrinsic" { + fn simd_cast(x: T) -> U; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + + unsafe { + simd_cast::(0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_cast::(0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_cast::(x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_cast::<_, i32x8>(x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i32x8` with length 8 + } +} diff --git a/src/test/compile-fail/simd-intrinsic-generic-comparison.rs b/src/test/compile-fail/simd-intrinsic-generic-comparison.rs new file mode 100644 index 0000000000000..617b03a87117b --- /dev/null +++ b/src/test/compile-fail/simd-intrinsic-generic-comparison.rs @@ -0,0 +1,75 @@ +// 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(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i16x8(i16, i16, i16, i16, + i16, i16, i16, i16); + +extern "platform-intrinsic" { + fn simd_eq(x: T, y: T) -> U; + fn simd_ne(x: T, y: T) -> U; + fn simd_lt(x: T, y: T) -> U; + fn simd_le(x: T, y: T) -> U; + fn simd_gt(x: T, y: T) -> U; + fn simd_ge(x: T, y: T) -> U; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + + unsafe { + simd_eq::(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_ne::(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_lt::(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_le::(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_gt::(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_ge::(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + + simd_eq::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_ne::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_lt::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_le::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_gt::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_ge::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + + simd_eq::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + simd_ne::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + simd_lt::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + simd_le::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + simd_gt::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + simd_ge::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + } +} diff --git a/src/test/compile-fail/simd-intrinsic-generic-elements.rs b/src/test/compile-fail/simd-intrinsic-generic-elements.rs new file mode 100644 index 0000000000000..b0198c411d567 --- /dev/null +++ b/src/test/compile-fail/simd-intrinsic-generic-elements.rs @@ -0,0 +1,97 @@ +// 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(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x3(i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x8(i32, i32, i32, i32, + i32, i32, i32, i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x2(f32, f32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x3(f32, f32, f32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x4(f32, f32, f32, f32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x8(f32, f32, f32, f32, + f32, f32, f32, f32); + +extern "platform-intrinsic" { + fn simd_insert(x: T, idx: u32, y: E) -> T; + fn simd_extract(x: T, idx: u32) -> E; + + fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; + fn simd_shuffle3(x: T, y: T, idx: [u32; 3]) -> U; + fn simd_shuffle4(x: T, y: T, idx: [u32; 4]) -> U; + fn simd_shuffle8(x: T, y: T, idx: [u32; 8]) -> U; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + + unsafe { + simd_insert(0, 0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_insert(x, 0, 1.0); + //~^ ERROR expected inserted type `i32` (element of input `i32x4`), found `f64` + simd_extract::<_, f32>(x, 0); + //~^ ERROR expected return type `i32` (element of input `i32x4`), found `f32` + + simd_shuffle2::(0, 0, [0; 2]); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_shuffle3::(0, 0, [0; 3]); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_shuffle4::(0, 0, [0; 4]); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_shuffle8::(0, 0, [0; 8]); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + + simd_shuffle2::<_, f32x2>(x, x, [0; 2]); +//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` + simd_shuffle3::<_, f32x3>(x, x, [0; 3]); +//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x3` with element type `f32` + simd_shuffle4::<_, f32x4>(x, x, [0; 4]); +//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` + simd_shuffle8::<_, f32x8>(x, x, [0; 8]); +//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` + + simd_shuffle2::<_, i32x8>(x, x, [0; 2]); + //~^ ERROR expected return type of length 2, found `i32x8` with length 8 + simd_shuffle3::<_, i32x4>(x, x, [0; 3]); + //~^ ERROR expected return type of length 3, found `i32x4` with length 4 + simd_shuffle4::<_, i32x3>(x, x, [0; 4]); + //~^ ERROR expected return type of length 4, found `i32x3` with length 3 + simd_shuffle8::<_, i32x2>(x, x, [0; 8]); + //~^ ERROR expected return type of length 8, found `i32x2` with length 2 + } +} diff --git a/src/test/compile-fail/simd-intrinsic-single-nominal-type.rs b/src/test/compile-fail/simd-intrinsic-single-nominal-type.rs new file mode 100644 index 0000000000000..0d0bf240f720a --- /dev/null +++ b/src/test/compile-fail/simd-intrinsic-single-nominal-type.rs @@ -0,0 +1,33 @@ +// 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(repr_simd, platform_intrinsics)] + +#[repr(simd)] +struct A(i16, i16, i16, i16, i16, i16, i16, i16); +#[repr(simd)] +struct B(i16, i16, i16, i16, i16, i16, i16, i16); + +// each intrinsic definition has to use the same nominal type for any +// vector structure throughout that declaration (i.e. every instance +// of i16x8 in each `fn ...;` needs to be either A or B) + +extern "platform-intrinsic" { + fn x86_mm_adds_epi16(x: A, y: A) -> B; + //~^ ERROR intrinsic return value has wrong type: found `B`, expected `A` + fn x86_mm_subs_epi16(x: A, y: B) -> A; + //~^ ERROR intrinsic argument 2 has wrong type: found `B`, expected `A` + + // ok: + fn x86_mm_max_epi16(x: B, y: B) -> B; + fn x86_mm_min_epi16(x: A, y: A) -> A; +} + +fn main() {} diff --git a/src/test/run-pass/issue-23037.rs b/src/test/compile-fail/simd-type-generic-monomorphisation.rs similarity index 67% rename from src/test/run-pass/issue-23037.rs rename to src/test/compile-fail/simd-type-generic-monomorphisation.rs index a8abbda32bdfc..336855eb5e18b 100644 --- a/src/test/run-pass/issue-23037.rs +++ b/src/test/compile-fail/simd-type-generic-monomorphisation.rs @@ -8,12 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(core_simd)] +#![feature(repr_simd, platform_intrinsics)] + +// error-pattern:monomorphising SIMD type `Simd2` with a non-machine element type `X` + +struct X(Vec); +#[repr(simd)] +struct Simd2(T, T); -use std::simd::i32x4; fn main() { - let foo = i32x4(1,2,3,4); - let bar = i32x4(40,30,20,10); - let baz = foo + bar; - assert!(baz.0 == 41 && baz.1 == 32 && baz.2 == 23 && baz.3 == 14); + let _ = Simd2(X(vec![]), X(vec![])); } diff --git a/src/test/compile-fail/simd-type.rs b/src/test/compile-fail/simd-type.rs index c47bc1747de3c..cde63aa0cd164 100644 --- a/src/test/compile-fail/simd-type.rs +++ b/src/test/compile-fail/simd-type.rs @@ -8,18 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(simd)] +#![feature(repr_simd)] -#[simd] -struct vec4(T, T, T, T); //~ ERROR SIMD vector cannot be generic - -#[simd] +#[repr(simd)] struct empty; //~ ERROR SIMD vector cannot be empty -#[simd] +#[repr(simd)] struct i64f64(i64, f64); //~ ERROR SIMD vector should be homogeneous -#[simd] +#[repr(simd)] struct int4(isize, isize, isize, isize); //~ ERROR SIMD vector element type should be machine type fn main() {} diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs index 4251579bbdcd1..eac38037b4bc1 100644 --- a/src/test/run-fail-fulldeps/qquote.rs +++ b/src/test/run-fail-fulldeps/qquote.rs @@ -23,9 +23,11 @@ use syntax::print::pprust; fn main() { let ps = syntax::parse::ParseSess::new(); + let mut feature_gated_cfgs = vec![]; let mut cx = syntax::ext::base::ExtCtxt::new( &ps, vec![], - syntax::ext::expand::ExpansionConfig::default("qquote".to_string())); + syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), + &mut feature_gated_cfgs); cx.bt_push(syntax::codemap::ExpnInfo { call_site: DUMMY_SP, callee: syntax::codemap::NameAndSpan { diff --git a/src/test/run-fail/overflowing-simd-lsh-1.rs b/src/test/run-fail/overflowing-simd-lsh-1.rs deleted file mode 100644 index a3bce00ee07cc..0000000000000 --- a/src/test/run-fail/overflowing-simd-lsh-1.rs +++ /dev/null @@ -1,23 +0,0 @@ -// 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. - -// error-pattern:thread '
' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::i32x4; - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn main() { - let _x = i32x4(1, 0, 0, 0) << id(i32x4(32, 0, 0, 0)); -} diff --git a/src/test/run-fail/overflowing-simd-lsh-2.rs b/src/test/run-fail/overflowing-simd-lsh-2.rs deleted file mode 100644 index e119bd03c8884..0000000000000 --- a/src/test/run-fail/overflowing-simd-lsh-2.rs +++ /dev/null @@ -1,23 +0,0 @@ -// 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. - -// error-pattern:thread '
' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::i32x4; - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn main() { - let _x = i32x4(1, 0, 0, 0) << id(i32x4(-1, 0, 0, 0)); -} diff --git a/src/test/run-fail/overflowing-simd-lsh-3.rs b/src/test/run-fail/overflowing-simd-lsh-3.rs deleted file mode 100644 index 4fb7fa958f041..0000000000000 --- a/src/test/run-fail/overflowing-simd-lsh-3.rs +++ /dev/null @@ -1,23 +0,0 @@ -// 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. - -// error-pattern:thread '
' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::u64x2; - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn main() { - let _x = u64x2(1, 0) << id(u64x2(64, 0)); -} diff --git a/src/test/run-fail/overflowing-simd-lsh-4.rs b/src/test/run-fail/overflowing-simd-lsh-4.rs deleted file mode 100644 index 2fc177ced9ddb..0000000000000 --- a/src/test/run-fail/overflowing-simd-lsh-4.rs +++ /dev/null @@ -1,49 +0,0 @@ -// 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. - -// error-pattern:thread '
' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -// This function is checking that our automatic truncation does not -// sidestep the overflow checking. - -#![feature(core_simd)] - -use std::simd::i8x16; - -fn eq_i8x16(i8x16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15): i8x16, - i8x16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15): i8x16) - -> bool -{ - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) - && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7) - && (x8 == y8) && (x9 == y9) && (x10 == y10) && (x11 == y11) - && (x12 == y12) && (x13 == y13) && (x14 == y14) && (x15 == y15) -} - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn main() { - // this signals overflow when checking is on - let x = i8x16(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) - << id(i8x16(17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); - - // ... but when checking is off, the fallback will truncate the - // input to its lower three bits (= 1). Note that this is *not* - // the behavior of the x86 processor for 8- and 16-bit types, - // but it is necessary to avoid undefined behavior from LLVM. - // - // We check that here, by ensuring the result has only been - // shifted by one place; if overflow checking is turned off, then - // this assertion will pass (and the compiletest driver will - // report that the test did not produce the error expected above). - assert!(eq_i8x16(x, i8x16(2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); -} diff --git a/src/test/run-fail/overflowing-simd-rsh-2.rs b/src/test/run-fail/overflowing-simd-rsh-2.rs deleted file mode 100644 index 2852e147f837d..0000000000000 --- a/src/test/run-fail/overflowing-simd-rsh-2.rs +++ /dev/null @@ -1,23 +0,0 @@ -// 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. - -// error-pattern:thread '
' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::i32x4; - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn main() { - let _x = i32x4(0, 0, 0, -1) >> id(i32x4(0, 0, 0, -1)); -} diff --git a/src/test/run-fail/overflowing-simd-rsh-3.rs b/src/test/run-fail/overflowing-simd-rsh-3.rs deleted file mode 100644 index 057eaa3f91aa0..0000000000000 --- a/src/test/run-fail/overflowing-simd-rsh-3.rs +++ /dev/null @@ -1,23 +0,0 @@ -// 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. - -// error-pattern:thread '
' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::i64x2; - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn main() { - let _x = i64x2(0, -1) >> id(i64x2(0, 64)); -} diff --git a/src/test/run-fail/overflowing-simd-rsh-4.rs b/src/test/run-fail/overflowing-simd-rsh-4.rs deleted file mode 100644 index a850fff691917..0000000000000 --- a/src/test/run-fail/overflowing-simd-rsh-4.rs +++ /dev/null @@ -1,49 +0,0 @@ -// 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. - -// error-pattern:thread '
' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -// This function is checking that our (type-based) automatic -// truncation does not sidestep the overflow checking. - -#![feature(core_simd)] - -use std::simd::i8x16; - -fn eq_i8x16(i8x16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15): i8x16, - i8x16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15): i8x16) - -> bool -{ - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) - && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7) - && (x8 == y8) && (x9 == y9) && (x10 == y10) && (x11 == y11) - && (x12 == y12) && (x13 == y13) && (x14 == y14) && (x15 == y15) -} - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn main() { - // this signals overflow when checking is on - let x = i8x16(2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) - >> id(i8x16(17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); - - // ... but when checking is off, the fallback will truncate the - // input to its lower three bits (= 1). Note that this is *not* - // the behavior of the x86 processor for 8- and 16-bit types, - // but it is necessary to avoid undefined behavior from LLVM. - // - // We check that here, by ensuring the result is not zero; if - // overflow checking is turned off, then this assertion will pass - // (and the compiletest driver will report that the test did not - // produce the error expected above). - assert!(eq_i8x16(x, i8x16(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); -} diff --git a/src/test/run-make/simd-ffi/simd.rs b/src/test/run-make/simd-ffi/simd.rs index 5576e8823716d..c0c4b1e7f3f31 100644 --- a/src/test/run-make/simd-ffi/simd.rs +++ b/src/test/run-make/simd-ffi/simd.rs @@ -15,12 +15,12 @@ #![feature(no_core)] #![no_core] -#![feature(simd, simd_ffi, link_llvm_intrinsics, lang_items)] +#![feature(repr_simd, simd_ffi, link_llvm_intrinsics, lang_items)] #[repr(C)] #[derive(Copy)] -#[simd] +#[repr(simd)] pub struct f32x4(f32, f32, f32, f32); @@ -35,7 +35,7 @@ pub fn foo(x: f32x4) -> f32x4 { #[repr(C)] #[derive(Copy)] -#[simd] +#[repr(simd)] pub struct i32x4(i32, i32, i32, i32); diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index 6670f200ba71e..e272a5fe4f6cd 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -19,9 +19,11 @@ use syntax::print::pprust::*; fn main() { let ps = syntax::parse::ParseSess::new(); + let mut feature_gated_cfgs = vec![]; let mut cx = syntax::ext::base::ExtCtxt::new( &ps, vec![], - syntax::ext::expand::ExpansionConfig::default("qquote".to_string())); + syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), + &mut feature_gated_cfgs); cx.bt_push(syntax::codemap::ExpnInfo { call_site: DUMMY_SP, callee: syntax::codemap::NameAndSpan { diff --git a/src/test/run-pass/issue-17170.rs b/src/test/run-pass/issue-17170.rs index ef1345259278d..c786064ba01ae 100644 --- a/src/test/run-pass/issue-17170.rs +++ b/src/test/run-pass/issue-17170.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(simd)] +#![feature(repr_simd)] -#[simd] +#[repr(simd)] struct T(f64, f64, f64); static X: T = T(0.0, 0.0, 0.0); diff --git a/src/test/run-pass/issue-24258.rs b/src/test/run-pass/issue-24258.rs deleted file mode 100644 index f56c3fefbe8f3..0000000000000 --- a/src/test/run-pass/issue-24258.rs +++ /dev/null @@ -1,26 +0,0 @@ -// 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. - -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::u32x4; - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn eq_u32x4(u32x4(x0, x1, x2, x3): u32x4, u32x4(y0, y1, y2, y3): u32x4) -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) -} - -fn main() { - assert!(eq_u32x4(u32x4(1, 1, 1, 1) << id(u32x4(1, 1, 1, 1)), u32x4(2, 2, 2, 2))); -} diff --git a/src/test/run-pass/simd-binop.rs b/src/test/run-pass/simd-binop.rs deleted file mode 100644 index 4f5119f6a84e9..0000000000000 --- a/src/test/run-pass/simd-binop.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2013-2014 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(core_simd)] - -use std::simd::{i32x4, f32x4, u32x4}; - -fn eq_u32x4(u32x4(x0, x1, x2, x3): u32x4, u32x4(y0, y1, y2, y3): u32x4) -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) -} - -fn eq_f32x4(f32x4(x0, x1, x2, x3): f32x4, f32x4(y0, y1, y2, y3): f32x4) -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) -} - -fn eq_i32x4(i32x4(x0, x1, x2, x3): i32x4, i32x4(y0, y1, y2, y3): i32x4) -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) -} - -pub fn main() { - // arithmetic operators - - assert!(eq_u32x4(u32x4(1, 2, 3, 4) + u32x4(4, 3, 2, 1), u32x4(5, 5, 5, 5))); - assert!(eq_u32x4(u32x4(4, 5, 6, 7) - u32x4(4, 3, 2, 1), u32x4(0, 2, 4, 6))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) * u32x4(4, 3, 2, 1), u32x4(4, 6, 6, 4))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) / u32x4(4, 3, 2, 1), u32x4(0, 0, 1, 4))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) & u32x4(4, 3, 2, 1), u32x4(0, 2, 2, 0))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) | u32x4(4, 3, 2, 1), u32x4(5, 3, 3, 5))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) ^ u32x4(4, 3, 2, 1), u32x4(5, 1, 1, 5))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) << u32x4(4, 3, 2, 1), u32x4(16, 16, 12, 8))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) >> u32x4(4, 3, 2, 1), u32x4(0, 0, 0, 2))); - - assert!(eq_i32x4(i32x4(1, 2, 3, 4) + i32x4(4, 3, 2, 1), i32x4(5, 5, 5, 5))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) - i32x4(4, 3, 2, 1), i32x4(-3, -1, 1, 3))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) * i32x4(4, 3, 2, 1), i32x4(4, 6, 6, 4))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) / i32x4(4, 3, 2, 1), i32x4(0, 0, 1, 4))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) & i32x4(4, 3, 2, 1), i32x4(0, 2, 2, 0))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) | i32x4(4, 3, 2, 1), i32x4(5, 3, 3, 5))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) ^ i32x4(4, 3, 2, 1), i32x4(5, 1, 1, 5))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) << i32x4(4, 3, 2, 1), i32x4(16, 16, 12, 8))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) >> i32x4(4, 3, 2, 1), i32x4(0, 0, 0, 2))); - - assert!(eq_f32x4(f32x4(1.0, 2.0, 3.0, 4.0) + f32x4(4.0, 3.0, 2.0, 1.0), - f32x4(5.0, 5.0, 5.0, 5.0))); - assert!(eq_f32x4(f32x4(1.0, 2.0, 3.0, 4.0) - f32x4(4.0, 3.0, 2.0, 1.0), - f32x4(-3.0, -1.0, 1.0, 3.0))); - assert!(eq_f32x4(f32x4(1.0, 2.0, 3.0, 4.0) * f32x4(4.0, 3.0, 2.0, 1.0), - f32x4(4.0, 6.0, 6.0, 4.0))); - assert!(eq_f32x4(f32x4(1.0, 2.0, 3.0, 4.0) / f32x4(4.0, 4.0, 2.0, 1.0), - f32x4(0.25, 0.5, 1.5, 4.0))); - - // comparison operators - - // check !0/-1 to ensure operators are using the correct signedness. - assert!(eq_u32x4(u32x4(1, 2, 3, !0) == u32x4(3, 2, 1, 0), u32x4(0, !0, 0, 0))); - assert!(eq_u32x4(u32x4(1, 2, 3, !0) != u32x4(3, 2, 1, 0), u32x4(!0, 0, !0, !0))); - assert!(eq_u32x4(u32x4(1, 2, 3, !0) < u32x4(3, 2, 1, 0), u32x4(!0, 0, 0, 0))); - assert!(eq_u32x4(u32x4(1, 2, 3, !0) <= u32x4(3, 2, 1, 0), u32x4(!0, !0, 0, 0))); - assert!(eq_u32x4(u32x4(1, 2, 3, !0) >= u32x4(3, 2, 1, 0), u32x4(0, !0, !0, !0))); - assert!(eq_u32x4(u32x4(1, 2, 3, !0) > u32x4(3, 2, 1, 0), u32x4(0, 0, !0, !0))); - - assert!(eq_i32x4(i32x4(1, 2, 3, -1) == i32x4(3, 2, 1, 0), i32x4(0, !0, 0, 0))); - assert!(eq_i32x4(i32x4(1, 2, 3, -1) != i32x4(3, 2, 1, 0), i32x4(!0, 0, !0, !0))); - assert!(eq_i32x4(i32x4(1, 2, 3, -1) < i32x4(3, 2, 1, 0), i32x4(!0, 0, 0, !0))); - assert!(eq_i32x4(i32x4(1, 2, 3, -1) <= i32x4(3, 2, 1, 0), i32x4(!0, !0, 0, !0))); - assert!(eq_i32x4(i32x4(1, 2, 3, -1) >= i32x4(3, 2, 1, 0), i32x4(0, !0, !0, 0))); - assert!(eq_i32x4(i32x4(1, 2, 3, -1) > i32x4(3, 2, 1, 0), i32x4(0, 0, !0, 0))); -} diff --git a/src/test/run-pass/simd-generics.rs b/src/test/run-pass/simd-generics.rs index 0e3d6b83a4be6..ef40a6ce96bd4 100644 --- a/src/test/run-pass/simd-generics.rs +++ b/src/test/run-pass/simd-generics.rs @@ -10,14 +10,18 @@ -#![feature(simd)] +#![feature(repr_simd, platform_intrinsics)] use std::ops; -#[simd] +#[repr(simd)] #[derive(Copy, Clone)] struct f32x4(f32, f32, f32, f32); +extern "platform-intrinsic" { + fn simd_add(x: T, y: T) -> T; +} + fn add>(lhs: T, rhs: T) -> T { lhs + rhs } @@ -26,7 +30,7 @@ impl ops::Add for f32x4 { type Output = f32x4; fn add(self, rhs: f32x4) -> f32x4 { - self + rhs + unsafe {simd_add(self, rhs)} } } diff --git a/src/test/run-pass/simd-intrinsic-generic-arithmetic.rs b/src/test/run-pass/simd-intrinsic-generic-arithmetic.rs new file mode 100644 index 0000000000000..5d4ecbb5f8172 --- /dev/null +++ b/src/test/run-pass/simd-intrinsic-generic-arithmetic.rs @@ -0,0 +1,111 @@ +// 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(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +struct i32x4(pub i32, pub i32, pub i32, pub i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +macro_rules! all_eq { + ($a: expr, $b: expr) => {{ + let a = $a; + let b = $b; + assert!(a.0 == b.0 && a.1 == b.1 && a.2 == b.2 && a.3 == b.3); + }} +} + +extern "platform-intrinsic" { + fn simd_add(x: T, y: T) -> T; + fn simd_sub(x: T, y: T) -> T; + fn simd_mul(x: T, y: T) -> T; + fn simd_div(x: T, y: T) -> T; + fn simd_shl(x: T, y: T) -> T; + fn simd_shr(x: T, y: T) -> T; + fn simd_and(x: T, y: T) -> T; + fn simd_or(x: T, y: T) -> T; + fn simd_xor(x: T, y: T) -> T; +} + +fn main() { + let x1 = i32x4(1, 2, 3, 4); + let y1 = u32x4(1, 2, 3, 4); + let z1 = f32x4(1.0, 2.0, 3.0, 4.0); + let x2 = i32x4(2, 3, 4, 5); + let y2 = u32x4(2, 3, 4, 5); + let z2 = f32x4(2.0, 3.0, 4.0, 5.0); + + unsafe { + all_eq!(simd_add(x1, x2), i32x4(3, 5, 7, 9)); + all_eq!(simd_add(x2, x1), i32x4(3, 5, 7, 9)); + all_eq!(simd_add(y1, y2), u32x4(3, 5, 7, 9)); + all_eq!(simd_add(y2, y1), u32x4(3, 5, 7, 9)); + all_eq!(simd_add(z1, z2), f32x4(3.0, 5.0, 7.0, 9.0)); + all_eq!(simd_add(z2, z1), f32x4(3.0, 5.0, 7.0, 9.0)); + + all_eq!(simd_mul(x1, x2), i32x4(2, 6, 12, 20)); + all_eq!(simd_mul(x2, x1), i32x4(2, 6, 12, 20)); + all_eq!(simd_mul(y1, y2), u32x4(2, 6, 12, 20)); + all_eq!(simd_mul(y2, y1), u32x4(2, 6, 12, 20)); + all_eq!(simd_mul(z1, z2), f32x4(2.0, 6.0, 12.0, 20.0)); + all_eq!(simd_mul(z2, z1), f32x4(2.0, 6.0, 12.0, 20.0)); + + all_eq!(simd_sub(x2, x1), i32x4(1, 1, 1, 1)); + all_eq!(simd_sub(x1, x2), i32x4(-1, -1, -1, -1)); + all_eq!(simd_sub(y2, y1), u32x4(1, 1, 1, 1)); + all_eq!(simd_sub(y1, y2), u32x4(!0, !0, !0, !0)); + all_eq!(simd_sub(z2, z1), f32x4(1.0, 1.0, 1.0, 1.0)); + all_eq!(simd_sub(z1, z2), f32x4(-1.0, -1.0, -1.0, -1.0)); + + all_eq!(simd_div(z1, z2), f32x4(1.0/2.0, 2.0/3.0, 3.0/4.0, 4.0/5.0)); + all_eq!(simd_div(z2, z1), f32x4(2.0/1.0, 3.0/2.0, 4.0/3.0, 5.0/4.0)); + + all_eq!(simd_shl(x1, x2), i32x4(1 << 2, 2 << 3, 3 << 4, 4 << 5)); + all_eq!(simd_shl(x2, x1), i32x4(2 << 1, 3 << 2, 4 << 3, 5 << 4)); + all_eq!(simd_shl(y1, y2), u32x4(1 << 2, 2 << 3, 3 << 4, 4 << 5)); + all_eq!(simd_shl(y2, y1), u32x4(2 << 1, 3 << 2, 4 << 3, 5 << 4)); + + // test right-shift by assuming left-shift is correct + all_eq!(simd_shr(simd_shl(x1, x2), x2), x1); + all_eq!(simd_shr(simd_shl(x2, x1), x1), x2); + all_eq!(simd_shr(simd_shl(y1, y2), y2), y1); + all_eq!(simd_shr(simd_shl(y2, y1), y1), y2); + + // ensure we get logical vs. arithmetic shifts correct + let (a, b, c, d) = (-12, -123, -1234, -12345); + all_eq!(simd_shr(i32x4(a, b, c, d), x1), i32x4(a >> 1, b >> 2, c >> 3, d >> 4)); + all_eq!(simd_shr(u32x4(a as u32, b as u32, c as u32, d as u32), y1), + u32x4((a as u32) >> 1, (b as u32) >> 2, (c as u32) >> 3, (d as u32) >> 4)); + + all_eq!(simd_and(x1, x2), i32x4(0, 2, 0, 4)); + all_eq!(simd_and(x2, x1), i32x4(0, 2, 0, 4)); + all_eq!(simd_and(y1, y2), u32x4(0, 2, 0, 4)); + all_eq!(simd_and(y2, y1), u32x4(0, 2, 0, 4)); + + all_eq!(simd_or(x1, x2), i32x4(3, 3, 7, 5)); + all_eq!(simd_or(x2, x1), i32x4(3, 3, 7, 5)); + all_eq!(simd_or(y1, y2), u32x4(3, 3, 7, 5)); + all_eq!(simd_or(y2, y1), u32x4(3, 3, 7, 5)); + + all_eq!(simd_xor(x1, x2), i32x4(3, 1, 7, 1)); + all_eq!(simd_xor(x2, x1), i32x4(3, 1, 7, 1)); + all_eq!(simd_xor(y1, y2), u32x4(3, 1, 7, 1)); + all_eq!(simd_xor(y2, y1), u32x4(3, 1, 7, 1)); + + } +} diff --git a/src/test/run-pass/simd-intrinsic-generic-cast.rs b/src/test/run-pass/simd-intrinsic-generic-cast.rs new file mode 100755 index 0000000000000..a20dd3ef72a54 --- /dev/null +++ b/src/test/run-pass/simd-intrinsic-generic-cast.rs @@ -0,0 +1,128 @@ +// 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(repr_simd, platform_intrinsics, concat_idents, + type_macros, test)] +#![allow(non_camel_case_types)] + +extern crate test; + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct i8x4(i8, i8, i8, i8); + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct u32x4(u32, u32, u32, u32); +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct u8x4(u8, u8, u8, u8); + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct f32x4(f32, f32, f32, f32); + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct f64x4(f64, f64, f64, f64); + + +extern "platform-intrinsic" { + fn simd_cast(x: T) -> U; +} + +const A: i32 = -1234567; +const B: i32 = 12345678; +const C: i32 = -123456789; +const D: i32 = 1234567890; + +trait Foo { + fn is_float() -> bool { false } + fn in_range(x: i32) -> bool; +} +impl Foo for i32 { + fn in_range(_: i32) -> bool { true } +} +impl Foo for i8 { + fn in_range(x: i32) -> bool { -128 <= x && x < 128 } +} +impl Foo for u32 { + fn in_range(x: i32) -> bool { 0 <= x } +} +impl Foo for u8 { + fn in_range(x: i32) -> bool { 0 <= x && x < 128 } +} +impl Foo for f32 { + fn is_float() -> bool { true } + fn in_range(_: i32) -> bool { true } +} +impl Foo for f64 { + fn is_float() -> bool { true } + fn in_range(_: i32) -> bool { true } +} + +fn main() { + macro_rules! test { + ($from: ident, $to: ident) => {{ + // force the casts to actually happen, or else LLVM/rustc + // may fold them and get slightly different results. + let (a, b, c, d) = test::black_box((A as $from, B as $from, C as $from, D as $from)); + // the SIMD vectors are all FOOx4, so we can concat_idents + // so we don't have to pass in the extra args to the macro + let mut from = simd_cast(concat_idents!($from, x4)(a, b, c, d)); + let mut to = concat_idents!($to, x4)(a as $to, + b as $to, + c as $to, + d as $to); + // assist type inference, it needs to know what `from` is + // for the `if` statements. + to == from; + + // there are platform differences for some out of range + // casts, so we just normalize such things: it's OK for + // "invalid" calculations to result in nonsense answers. + // (E.g. negative float to unsigned integer goes through a + // library routine on the default i686 platforms, and the + // implementation of that routine differs on e.g. Linux + // vs. OSX, resulting in different answers.) + if $from::is_float() { + if !$to::in_range(A) { from.0 = 0 as $to; to.0 = 0 as $to; } + if !$to::in_range(B) { from.1 = 0 as $to; to.1 = 0 as $to; } + if !$to::in_range(C) { from.2 = 0 as $to; to.2 = 0 as $to; } + if !$to::in_range(D) { from.3 = 0 as $to; to.3 = 0 as $to; } + } + + assert!(to == from, + "{} -> {} ({:?} != {:?})", stringify!($from), stringify!($to), + from, to); + }} + } + macro_rules! tests { + (: $($to: ident),*) => { () }; + // repeating the list twice is easier than writing a cartesian + // product macro + ($from: ident $(, $from_: ident)*: $($to: ident),*) => { + fn $from() { unsafe { $( test!($from, $to); )* } } + tests!($($from_),*: $($to),*) + }; + ($($types: ident),*) => {{ + tests!($($types),* : $($types),*); + $($types();)* + }} + } + + // test various combinations, including truncation, + // signed/unsigned extension, and floating point casts. + tests!(i32, i8, u32, u8, f32); + tests!(i32, u32, f32, f64) +} diff --git a/src/test/run-pass/simd-intrinsic-generic-comparison.rs b/src/test/run-pass/simd-intrinsic-generic-comparison.rs new file mode 100644 index 0000000000000..5802fb30bd680 --- /dev/null +++ b/src/test/run-pass/simd-intrinsic-generic-comparison.rs @@ -0,0 +1,113 @@ +// 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(repr_simd, platform_intrinsics, concat_idents)] +#![allow(non_camel_case_types)] + +use std::f32::NAN; + +#[repr(simd)] +#[derive(Copy, Clone)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +struct u32x4(pub u32, pub u32, pub u32, pub u32); +#[repr(simd)] +#[derive(Copy, Clone)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_eq(x: T, y: T) -> U; + fn simd_ne(x: T, y: T) -> U; + fn simd_lt(x: T, y: T) -> U; + fn simd_le(x: T, y: T) -> U; + fn simd_gt(x: T, y: T) -> U; + fn simd_ge(x: T, y: T) -> U; +} + +macro_rules! cmp { + ($method: ident($lhs: expr, $rhs: expr)) => {{ + let lhs = $lhs; + let rhs = $rhs; + let e: u32x4 = concat_idents!(simd_, $method)($lhs, $rhs); + // assume the scalar version is correct/the behaviour we want. + assert!((e.0 != 0) == lhs.0 .$method(&rhs.0)); + assert!((e.1 != 0) == lhs.1 .$method(&rhs.1)); + assert!((e.2 != 0) == lhs.2 .$method(&rhs.2)); + assert!((e.3 != 0) == lhs.3 .$method(&rhs.3)); + }} +} +macro_rules! tests { + ($($lhs: ident, $rhs: ident;)*) => {{ + $( + (|| { + cmp!(eq($lhs, $rhs)); + cmp!(ne($lhs, $rhs)); + + // test both directions + cmp!(lt($lhs, $rhs)); + cmp!(lt($rhs, $lhs)); + + cmp!(le($lhs, $rhs)); + cmp!(le($rhs, $lhs)); + + cmp!(gt($lhs, $rhs)); + cmp!(gt($rhs, $lhs)); + + cmp!(ge($lhs, $rhs)); + cmp!(ge($rhs, $lhs)); + })(); + )* + }} +} +fn main() { + // 13 vs. -100 tests that we get signed vs. unsigned comparisons + // correct (i32: 13 > -100, u32: 13 < -100). let i1 = i32x4(10, -11, 12, 13); + let i1 = i32x4(10, -11, 12, 13); + let i2 = i32x4(5, -5, 20, -100); + let i3 = i32x4(10, -11, 20, -100); + + let u1 = u32x4(10, !11+1, 12, 13); + let u2 = u32x4(5, !5+1, 20, !100+1); + let u3 = u32x4(10, !11+1, 20, !100+1); + + let f1 = f32x4(10.0, -11.0, 12.0, 13.0); + let f2 = f32x4(5.0, -5.0, 20.0, -100.0); + let f3 = f32x4(10.0, -11.0, 20.0, -100.0); + + unsafe { + tests! { + i1, i1; + u1, u1; + f1, f1; + + i1, i2; + u1, u2; + f1, f2; + + i1, i3; + u1, u3; + f1, f3; + } + } + + // NAN comparisons are special: + // -11 (*) 13 + // -5 -100 (*) + let f4 = f32x4(NAN, f1.1, NAN, f2.3); + + unsafe { + tests! { + f1, f4; + f2, f4; + f4, f4; + } + } +} diff --git a/src/test/run-pass/simd-intrinsic-generic-elements.rs b/src/test/run-pass/simd-intrinsic-generic-elements.rs new file mode 100644 index 0000000000000..f0444c2717056 --- /dev/null +++ b/src/test/run-pass/simd-intrinsic-generic-elements.rs @@ -0,0 +1,132 @@ +// 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(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x3(i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x8(i32, i32, i32, i32, + i32, i32, i32, i32); + +extern "platform-intrinsic" { + fn simd_insert(x: T, idx: u32, y: E) -> T; + fn simd_extract(x: T, idx: u32) -> E; + + fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; + fn simd_shuffle3(x: T, y: T, idx: [u32; 3]) -> U; + fn simd_shuffle4(x: T, y: T, idx: [u32; 4]) -> U; + fn simd_shuffle8(x: T, y: T, idx: [u32; 8]) -> U; +} + +macro_rules! all_eq { + ($a: expr, $b: expr) => {{ + let a = $a; + let b = $b; + // type inference works better with the concrete type on the + // left, but humans work better with the expected on the + // right. + assert!(b == a, + "{:?} != {:?}", a, b); + }} +} + +fn main() { + let x2 = i32x2(20, 21); + let x3 = i32x3(30, 31, 32); + let x4 = i32x4(40, 41, 42, 43); + let x8 = i32x8(80, 81, 82, 83, 84, 85, 86, 87); + unsafe { + all_eq!(simd_insert(x2, 0, 100), i32x2(100, 21)); + all_eq!(simd_insert(x2, 1, 100), i32x2(20, 100)); + + all_eq!(simd_insert(x3, 0, 100), i32x3(100, 31, 32)); + all_eq!(simd_insert(x3, 1, 100), i32x3(30, 100, 32)); + all_eq!(simd_insert(x3, 2, 100), i32x3(30, 31, 100)); + + all_eq!(simd_insert(x4, 0, 100), i32x4(100, 41, 42, 43)); + all_eq!(simd_insert(x4, 1, 100), i32x4(40, 100, 42, 43)); + all_eq!(simd_insert(x4, 2, 100), i32x4(40, 41, 100, 43)); + all_eq!(simd_insert(x4, 3, 100), i32x4(40, 41, 42, 100)); + + all_eq!(simd_insert(x8, 0, 100), i32x8(100, 81, 82, 83, 84, 85, 86, 87)); + all_eq!(simd_insert(x8, 1, 100), i32x8(80, 100, 82, 83, 84, 85, 86, 87)); + all_eq!(simd_insert(x8, 2, 100), i32x8(80, 81, 100, 83, 84, 85, 86, 87)); + all_eq!(simd_insert(x8, 3, 100), i32x8(80, 81, 82, 100, 84, 85, 86, 87)); + all_eq!(simd_insert(x8, 4, 100), i32x8(80, 81, 82, 83, 100, 85, 86, 87)); + all_eq!(simd_insert(x8, 5, 100), i32x8(80, 81, 82, 83, 84, 100, 86, 87)); + all_eq!(simd_insert(x8, 6, 100), i32x8(80, 81, 82, 83, 84, 85, 100, 87)); + all_eq!(simd_insert(x8, 7, 100), i32x8(80, 81, 82, 83, 84, 85, 86, 100)); + + all_eq!(simd_extract(x2, 0), 20); + all_eq!(simd_extract(x2, 1), 21); + + all_eq!(simd_extract(x3, 0), 30); + all_eq!(simd_extract(x3, 1), 31); + all_eq!(simd_extract(x3, 2), 32); + + all_eq!(simd_extract(x4, 0), 40); + all_eq!(simd_extract(x4, 1), 41); + all_eq!(simd_extract(x4, 2), 42); + all_eq!(simd_extract(x4, 3), 43); + + all_eq!(simd_extract(x8, 0), 80); + all_eq!(simd_extract(x8, 1), 81); + all_eq!(simd_extract(x8, 2), 82); + all_eq!(simd_extract(x8, 3), 83); + all_eq!(simd_extract(x8, 4), 84); + all_eq!(simd_extract(x8, 5), 85); + all_eq!(simd_extract(x8, 6), 86); + all_eq!(simd_extract(x8, 7), 87); + } + + let y2 = i32x2(120, 121); + let y3 = i32x3(130, 131, 132); + let y4 = i32x4(140, 141, 142, 143); + let y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187); + unsafe { + all_eq!(simd_shuffle2(x2, y2, [3, 0]), i32x2(121, 20)); + all_eq!(simd_shuffle3(x2, y2, [3, 0, 1]), i32x3(121, 20, 21)); + all_eq!(simd_shuffle4(x2, y2, [3, 0, 1, 2]), i32x4(121, 20, 21, 120)); + all_eq!(simd_shuffle8(x2, y2, [3, 0, 1, 2, 1, 2, 3, 0]), + i32x8(121, 20, 21, 120, 21, 120, 121, 20)); + + all_eq!(simd_shuffle2(x3, y3, [4, 2]), i32x2(131, 32)); + all_eq!(simd_shuffle3(x3, y3, [4, 2, 3]), i32x3(131, 32, 130)); + all_eq!(simd_shuffle4(x3, y3, [4, 2, 3, 0]), i32x4(131, 32, 130, 30)); + all_eq!(simd_shuffle8(x3, y3, [4, 2, 3, 0, 1, 5, 5, 1]), + i32x8(131, 32, 130, 30, 31, 132, 132, 31)); + + all_eq!(simd_shuffle2(x4, y4, [7, 2]), i32x2(143, 42)); + all_eq!(simd_shuffle3(x4, y4, [7, 2, 5]), i32x3(143, 42, 141)); + all_eq!(simd_shuffle4(x4, y4, [7, 2, 5, 0]), i32x4(143, 42, 141, 40)); + all_eq!(simd_shuffle8(x4, y4, [7, 2, 5, 0, 3, 6, 4, 1]), + i32x8(143, 42, 141, 40, 43, 142, 140, 41)); + + all_eq!(simd_shuffle2(x8, y8, [11, 5]), i32x2(183, 85)); + all_eq!(simd_shuffle3(x8, y8, [11, 5, 15]), i32x3(183, 85, 187)); + all_eq!(simd_shuffle4(x8, y8, [11, 5, 15, 0]), i32x4(183, 85, 187, 80)); + all_eq!(simd_shuffle8(x8, y8, [11, 5, 15, 0, 3, 8, 12, 1]), + i32x8(183, 85, 187, 80, 83, 180, 184, 81)); + } + +} diff --git a/src/test/run-pass/simd-shift-near-oflo.rs b/src/test/run-pass/simd-shift-near-oflo.rs deleted file mode 100644 index fee4637f07f21..0000000000000 --- a/src/test/run-pass/simd-shift-near-oflo.rs +++ /dev/null @@ -1,154 +0,0 @@ -// 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. - -// compile-flags: -C debug-assertions - -// Check that we do *not* overflow on a number of edge cases. -// (compare with test/run-fail/overflowing-{lsh,rsh}*.rs) - -#![feature(core_simd)] - -use std::simd::{i8x16, i16x8, i32x4, i64x2, u8x16, u16x8, u32x4, u64x2}; - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn single_i8x16(x: i8) -> i8x16 { i8x16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x) } -fn single_u8x16(x: u8) -> u8x16 { u8x16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x) } -fn single_i16x8(x: i16) -> i16x8 { i16x8(0, 0, 0, 0, 0, 0, 0, x) } -fn single_u16x8(x: u16) -> u16x8 { u16x8(0, 0, 0, 0, 0, 0, 0, x) } -fn single_i32x4(x: i32) -> i32x4 { i32x4(0, 0, 0, x) } -fn single_u32x4(x: u32) -> u32x4 { u32x4(0, 0, 0, x) } -fn single_i64x2(x: i64) -> i64x2 { i64x2(0, x) } -fn single_u64x2(x: u64) -> u64x2 { u64x2(0, x) } - -fn eq_i8x16(i8x16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15): i8x16, - i8x16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15): i8x16) - -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) - && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7) - && (x8 == y8) && (x9 == y9) && (x10 == y10) && (x11 == y11) - && (x12 == y12) && (x13 == y13) && (x14 == y14) && (x15 == y15) -} -fn eq_u8x16(u8x16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15): u8x16, - u8x16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15): u8x16) - -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) - && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7) - && (x8 == y8) && (x9 == y9) && (x10 == y10) && (x11 == y11) - && (x12 == y12) && (x13 == y13) && (x14 == y14) && (x15 == y15) -} -fn eq_i16x8(i16x8(x0, x1, x2, x3, x4, x5, x6, x7): i16x8, - i16x8(y0, y1, y2, y3, y4, y5, y6, y7): i16x8) -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) - && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7) -} -fn eq_u16x8(u16x8(x0, x1, x2, x3, x4, x5, x6, x7): u16x8, - u16x8(y0, y1, y2, y3, y4, y5, y6, y7): u16x8) -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) - && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7) -} -fn eq_i32x4(i32x4(x0, x1, x2, x3): i32x4, i32x4(y0, y1, y2, y3): i32x4) -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) -} -fn eq_u32x4(u32x4(x0, x1, x2, x3): u32x4, u32x4(y0, y1, y2, y3): u32x4) -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) -} -fn eq_i64x2(i64x2(x0, x1): i64x2, i64x2(y0, y1): i64x2) -> bool { - (x0 == y0) && (x1 == y1) -} -fn eq_u64x2(u64x2(x0, x1): u64x2, u64x2(y0, y1): u64x2) -> bool { - (x0 == y0) && (x1 == y1) -} - -fn main() { - test_left_shift(); - test_right_shift(); -} - -fn test_left_shift() { - // negative rhs can panic, but values in [0,N-1] are okay for iN - - macro_rules! tests { - ($single:ident, $eq:ident, $max_rhs:expr, $expect:expr) => { { - let x = $single(1) << id($single(0)); - assert!($eq(x, $single(1))); - let x = $single(1) << id($single($max_rhs)); - assert!($eq(x, $single($expect))); - // high-order bits on LHS are silently discarded without panic. - let x = $single(3) << id($single($max_rhs)); - assert!($eq(x, $single($expect))); - } } - } - - let x = single_i8x16(1) << id(single_i8x16(0)); - assert!(eq_i8x16(x, single_i8x16(1))); - let x = single_u8x16(1) << id(single_u8x16(0)); - assert!(eq_u8x16(x, single_u8x16(1))); - let x = single_i8x16(1) << id(single_i8x16(7)); - assert!(eq_i8x16(x, single_i8x16(std::i8::MIN))); - let x = single_u8x16(1) << id(single_u8x16(7)); - assert!(eq_u8x16(x, single_u8x16(0x80))); - // high-order bits on LHS are silently discarded without panic. - let x = single_i8x16(3) << id(single_i8x16(7)); - assert!(eq_i8x16(x, single_i8x16(std::i8::MIN))); - let x = single_u8x16(3) << id(single_u8x16(7)); - assert!(eq_u8x16(x, single_u8x16(0x80))); - - // above is (approximately) expanded from: - tests!(single_i8x16, eq_i8x16, 7, std::i8::MIN); - tests!(single_u8x16, eq_u8x16, 7, 0x80_u8); - - tests!(single_i16x8, eq_i16x8, 15, std::i16::MIN); - tests!(single_u16x8, eq_u16x8, 15, 0x8000_u16); - - tests!(single_i32x4, eq_i32x4, 31, std::i32::MIN); - tests!(single_u32x4, eq_u32x4, 31, 0x8000_0000_u32); - - tests!(single_i64x2, eq_i64x2, 63, std::i64::MIN); - tests!(single_u64x2, eq_u64x2, 63, 0x8000_0000_0000_0000_u64); -} - -fn test_right_shift() { - // negative rhs can panic, but values in [0,N-1] are okay for iN - - macro_rules! tests { - ($single_i:ident, $eq_i:ident, $single_u:ident, $eq_u:ident, - $max_rhs:expr, $signbit_i:expr, $highbit_i:expr, $highbit_u:expr) => { { - let x = $single_i(1) >> id($single_i(0)); - assert!($eq_i(x, $single_i(1))); - let x = $single_u(1) >> id($single_u(0)); - assert!($eq_u(x, $single_u(1))); - let x = $single_u($highbit_i) >> id($single_u($max_rhs-1)); - assert!($eq_u(x, $single_u(1))); - let x = $single_u($highbit_u) >> id($single_u($max_rhs)); - assert!($eq_u(x, $single_u(1))); - // sign-bit is carried by arithmetic right shift - let x = $single_i($signbit_i) >> id($single_i($max_rhs)); - assert!($eq_i(x, $single_i(-1))); - // low-order bits on LHS are silently discarded without panic. - let x = $single_u($highbit_i + 1) >> id($single_u($max_rhs-1)); - assert!($eq_u(x, $single_u(1))); - let x = $single_u($highbit_u + 1) >> id($single_u($max_rhs)); - assert!($eq_u(x, $single_u(1))); - let x = $single_i($signbit_i + 1) >> id($single_i($max_rhs)); - assert!($eq_i(x, $single_i(-1))); - } } - } - - tests!(single_i8x16, eq_i8x16, single_u8x16, eq_u8x16, - 7, std::i8::MIN, 0x40_u8, 0x80_u8); - tests!(single_i16x8, eq_i16x8, single_u16x8, eq_u16x8, - 15, std::i16::MIN, 0x4000_u16, 0x8000_u16); - tests!(single_i32x4, eq_i32x4, single_u32x4, eq_u32x4, - 31, std::i32::MIN, 0x4000_0000_u32, 0x8000_0000_u32); - tests!(single_i64x2, eq_i64x2, single_u64x2, eq_u64x2, - 63, std::i64::MIN, 0x4000_0000_0000_0000_u64, 0x8000_0000_0000_0000_u64); -} diff --git a/src/test/run-pass/simd-size-align.rs b/src/test/run-pass/simd-size-align.rs index 025b2a77375e8..b8d7cd8414176 100644 --- a/src/test/run-pass/simd-size-align.rs +++ b/src/test/run-pass/simd-size-align.rs @@ -9,7 +9,7 @@ // except according to those terms. -#![feature(simd)] +#![feature(repr_simd)] #![allow(non_camel_case_types)] use std::mem; @@ -46,26 +46,26 @@ fn main() { check::(); } -#[simd] struct u8x2(u8, u8); -#[simd] struct u8x3(u8, u8, u8); -#[simd] struct u8x4(u8, u8, u8, u8); -#[simd] struct u8x5(u8, u8, u8, u8, u8); -#[simd] struct u8x6(u8, u8, u8, u8, u8, u8); -#[simd] struct u8x7(u8, u8, u8, u8, u8, u8, u8); -#[simd] struct u8x8(u8, u8, u8, u8, u8, u8, u8, u8); +#[repr(simd)] struct u8x2(u8, u8); +#[repr(simd)] struct u8x3(u8, u8, u8); +#[repr(simd)] struct u8x4(u8, u8, u8, u8); +#[repr(simd)] struct u8x5(u8, u8, u8, u8, u8); +#[repr(simd)] struct u8x6(u8, u8, u8, u8, u8, u8); +#[repr(simd)] struct u8x7(u8, u8, u8, u8, u8, u8, u8); +#[repr(simd)] struct u8x8(u8, u8, u8, u8, u8, u8, u8, u8); -#[simd] struct i16x2(i16, i16); -#[simd] struct i16x3(i16, i16, i16); -#[simd] struct i16x4(i16, i16, i16, i16); -#[simd] struct i16x5(i16, i16, i16, i16, i16); -#[simd] struct i16x6(i16, i16, i16, i16, i16, i16); -#[simd] struct i16x7(i16, i16, i16, i16, i16, i16, i16); -#[simd] struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); +#[repr(simd)] struct i16x2(i16, i16); +#[repr(simd)] struct i16x3(i16, i16, i16); +#[repr(simd)] struct i16x4(i16, i16, i16, i16); +#[repr(simd)] struct i16x5(i16, i16, i16, i16, i16); +#[repr(simd)] struct i16x6(i16, i16, i16, i16, i16, i16); +#[repr(simd)] struct i16x7(i16, i16, i16, i16, i16, i16, i16); +#[repr(simd)] struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); -#[simd] struct f32x2(f32, f32); -#[simd] struct f32x3(f32, f32, f32); -#[simd] struct f32x4(f32, f32, f32, f32); -#[simd] struct f32x5(f32, f32, f32, f32, f32); -#[simd] struct f32x6(f32, f32, f32, f32, f32, f32); -#[simd] struct f32x7(f32, f32, f32, f32, f32, f32, f32); -#[simd] struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); +#[repr(simd)] struct f32x2(f32, f32); +#[repr(simd)] struct f32x3(f32, f32, f32); +#[repr(simd)] struct f32x4(f32, f32, f32, f32); +#[repr(simd)] struct f32x5(f32, f32, f32, f32, f32); +#[repr(simd)] struct f32x6(f32, f32, f32, f32, f32, f32); +#[repr(simd)] struct f32x7(f32, f32, f32, f32, f32, f32, f32); +#[repr(simd)] struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); diff --git a/src/test/run-pass/simd-type.rs b/src/test/run-pass/simd-type.rs index 540666f41ae2b..2883b80a25b9e 100644 --- a/src/test/run-pass/simd-type.rs +++ b/src/test/run-pass/simd-type.rs @@ -11,9 +11,9 @@ // pretty-expanded FIXME #23616 -#![feature(simd)] +#![feature(repr_simd)] -#[simd] +#[repr(simd)] struct RGBA { r: f32, g: f32,