diff options
| author | bors <bors@rust-lang.org> | 2015-08-17 23:41:36 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-08-17 23:41:36 +0000 |
| commit | e35fd748114c22df6d08991980c4f7e199414497 (patch) | |
| tree | 1741be330092cf63fa429a6c529430a55db52a54 | |
| parent | 6d992728c331128810704d16d8026aa4fa2e0c87 (diff) | |
| parent | 02e97342c136d2d13411ebd0a687100d8be248e0 (diff) | |
| download | rust-e35fd748114c22df6d08991980c4f7e199414497.tar.gz rust-e35fd748114c22df6d08991980c4f7e199414497.zip | |
Auto merge of #27169 - huonw:simd, r=alexcrichton
This implements https://github.com/rust-lang/rfcs/pull/1199 (except for doing all the platform intrinsics). Things remaining for SIMD (not necessarily in this PR): - [x] I (@huonw) am signed up to ensure the compiler matches the RFC, when it lands - [x] the platform specific intrinsics aren't properly type checked at the moment (LLVM will throw a "random" assertion) - [ ] there's a lot of useful intrinsics that are missing, including whole platforms (mips, powerpc) - [ ] the target-feature `cfg` detection/adding is not so great at the moment - [x] I think the platform specific intrinsics should go in their own `extern` ABI (i.e. not `"rust-intrinsic"`) (I'm adjusting the RFC to reflect the latter.) I think it would be very nice for this to land without requiring the RFC to land first, because of the first point, and because this is the only way for any further work to happen/be experimented with, without requiring people to build/install/multirust a compiler from a custom branch. r? @alexcrichton
77 files changed, 3032 insertions, 1031 deletions
diff --git a/mk/crates.mk b/mk/crates.mk index af2a663b61d..aeb336f844f 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 ae85e2712ce..e226e9fa154 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 b06c0241093..fb39b3accc3 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<T>(x: T, y: T) -> T; + fn simd_sub<T>(x: T, y: T) -> T; + fn simd_mul<T>(x: T, y: T) -> T; + fn simd_div<T>(x: T, y: T) -> T; + fn simd_shl<T>(x: T, y: T) -> T; + fn simd_shr<T>(x: T, y: T) -> T; + fn simd_and<T>(x: T, y: T) -> T; + fn simd_or<T>(x: T, y: T) -> T; + fn simd_xor<T>(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 00000000000..7ecd08bea35 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! SIMD vectors. +//! +//! 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 c34b2ea58dc..3f182b4d2b5 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 91638f0de7e..d9e6e8c12f1 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 967eb3ff74f..d7a58f4cdd0 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<VariantDefData<'tcx, 'container>>) -> 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 263a8e14807..346e7a7bf98 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 1d440af2697..60eaffd71cb 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 00000000000..ca76046acf0 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +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 f5819316477..523ab7b527a 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 00000000000..e7b11e45fd6 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +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<Intrinsic> { + 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 00000000000..f29f7e384b4 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +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<Intrinsic> { + 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 00000000000..134b4c66419 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![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<Type>, + pub output: Type, + + pub definition: IntrinsicDef, +} + +#[derive(Clone, Hash, Eq, PartialEq)] +pub enum Type { + Integer(u8), + Float(u8), + Pointer(Box<Type>), + Vector(Box<Type>, 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<Intrinsic> { + 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 00000000000..cab7ab2fecb --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +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<Intrinsic> { + 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 6d91ae6fed6..23f21f337f3 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 326d1e2361e..0d34cce919a 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 1982f04195f..6be2bb08464 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 d0d5b46ab28..d201114fd82 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 c5043f867de..9ba45e0d481 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 225ff52a63c..b316d105d0c 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 33e5d814eb1..ded748e9894 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<ValueRef> { 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_<operation>[_<ordering>]", 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::<Vec<_>>(); + 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<ast::Expr>]>, + 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<Vec<_>> = (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 c2d1d19935a..6527136b602 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 5991d61a1e4..2e2f11bd133 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 00000000000..636f17db38c --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! 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<ty::Ty<'tcx>>, + 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 be008d52285..aaa0111cae0 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, 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 b139cb45bf2..59856a4a9c6 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 7d3fea7813c..b0f07c14bc9 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 08fd4d8dee5..82a605cd14f 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 ba9caa2f3f3..81399938f27 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<String>, 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 655fa04c264..bc7252fa33a 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 847ba47ff72..78f969bfbeb 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 7078ee92085..d36ca709c5c 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 50c86a80b4a..c0fe541ead5 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 0bcd97cfe87..2d72c8fe2a4 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<usize> { + 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<usize> { + 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 5e16465b4d4..7540c2ff831 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<MetaItem>], cfg: &ast::MetaItem) -> bool { +pub fn cfg_matches(diagnostic: &SpanHandler, cfgs: &[P<MetaItem>], cfg: &ast::MetaItem, + feature_gated_cfgs: &mut Vec<GatedCfg>) -> 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<ReprAt // Can't use "extern" because it's not a lexical identifier. "C" => 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 366806bc19b..faf0b51c8de 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<F> 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<GatedCfg>) + -> 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<F> fold::Folder for Context<F> where F: FnMut(&[ast::Attribute]) -> bool { @@ -248,7 +252,8 @@ fn foreign_item_in_cfg<F>(cx: &mut Context<F>, 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<ast::MetaItem>], attrs: &[ast::Attribute]) -> bool { +fn in_cfg(diagnostic: &SpanHandler, cfg: &[P<ast::MetaItem>], attrs: &[ast::Attribute], + feature_gated_cfgs: &mut Vec<GatedCfg>) -> 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<ast::MetaItem>], 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<GatedCfg> } // 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<GatedCfg>) -> 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<ast::Attribute> { 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 d4b5e67eeb4..ef11a2bd66e 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<GatedCfg>, pub mod_path: Vec<ast::Ident> , pub exported_macros: Vec<ast::MacroDef>, @@ -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<GatedCfg>) -> 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 8af7fb7b268..aa654e30530 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 1f4860b7ec1..f8f63e94ee5 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 e61a0b5401e..4f89b3494d4 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<ast::MacroDef>, user_exts: Vec<NamedSyntaxExtension>, + feature_gated_cfgs: &mut Vec<GatedCfg>, 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 { "<test>".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 { "<test>".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 694a1a43f59..f5a0a2f4718 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<cmp::Ordering> { + Some(self.cmp(other)) + } +} + +impl GatedCfg { + pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> { + 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<F>(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 ea99291d6c2..26fb287ce35 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 b3591477022..a6c77eaf7c6 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -91,7 +91,7 @@ fn mult<F>(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 index dffd627a084..7832e1c7c51 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 '<main>' 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<T>(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 index 59c44bff3c7..fdafb2ad950 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 32c50b1b8c1..f7bd2fcbceb 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 feffe5c0b06..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// 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 00000000000..effa1ed04d8 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(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 00000000000..35c368f4cbe --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(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<T>(x: T, y: T) -> T; + fn simd_sub<T>(x: T, y: T) -> T; + fn simd_mul<T>(x: T, y: T) -> T; + fn simd_div<T>(x: T, y: T) -> T; + fn simd_shl<T>(x: T, y: T) -> T; + fn simd_shr<T>(x: T, y: T) -> T; + fn simd_and<T>(x: T, y: T) -> T; + fn simd_or<T>(x: T, y: T) -> T; + fn simd_xor<T>(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 00000000000..4999b790b13 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(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<T, U>(x: T) -> U; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + + unsafe { + simd_cast::<i32, i32>(0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_cast::<i32, i32x4>(0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_cast::<i32x4, i32>(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 00000000000..617b03a8711 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(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<T, U>(x: T, y: T) -> U; + fn simd_ne<T, U>(x: T, y: T) -> U; + fn simd_lt<T, U>(x: T, y: T) -> U; + fn simd_le<T, U>(x: T, y: T) -> U; + fn simd_gt<T, U>(x: T, y: T) -> U; + fn simd_ge<T, U>(x: T, y: T) -> U; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + + unsafe { + simd_eq::<i32, i32>(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_ne::<i32, i32>(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_lt::<i32, i32>(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_le::<i32, i32>(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_gt::<i32, i32>(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_ge::<i32, i32>(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 00000000000..b0198c411d5 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(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<T, E>(x: T, idx: u32, y: E) -> T; + fn simd_extract<T, E>(x: T, idx: u32) -> E; + + fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U; + fn simd_shuffle3<T, U>(x: T, y: T, idx: [u32; 3]) -> U; + fn simd_shuffle4<T, U>(x: T, y: T, idx: [u32; 4]) -> U; + fn simd_shuffle8<T, U>(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::<i32, i32>(0, 0, [0; 2]); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_shuffle3::<i32, i32>(0, 0, [0; 3]); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_shuffle4::<i32, i32>(0, 0, [0; 4]); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_shuffle8::<i32, i32>(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 00000000000..0d0bf240f72 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(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 index a8abbda32bd..336855eb5e1 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<X>` with a non-machine element type `X` + +struct X(Vec<i32>); +#[repr(simd)] +struct Simd2<T>(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 c47bc1747de..cde63aa0cd1 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, 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 4251579bbdc..eac38037b4b 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 a3bce00ee07..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:thread '<main>' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::i32x4; - -// (Work around constant-evaluation) -fn id<T>(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 e119bd03c88..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:thread '<main>' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::i32x4; - -// (Work around constant-evaluation) -fn id<T>(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 4fb7fa958f0..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:thread '<main>' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::u64x2; - -// (Work around constant-evaluation) -fn id<T>(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 2fc177ced9d..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:thread '<main>' 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<T>(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 2852e147f83..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:thread '<main>' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::i32x4; - -// (Work around constant-evaluation) -fn id<T>(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 057eaa3f91a..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:thread '<main>' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::i64x2; - -// (Work around constant-evaluation) -fn id<T>(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 a850fff6919..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:thread '<main>' 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<T>(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 5576e882371..c0c4b1e7f3f 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 6670f200ba7..e272a5fe4f6 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 ef134525927..c786064ba01 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 f56c3fefbe8..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::u32x4; - -// (Work around constant-evaluation) -fn id<T>(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 4f5119f6a84..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -#![feature(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 0e3d6b83a4b..ef40a6ce96b 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<T>(x: T, y: T) -> T; +} + fn add<T: ops::Add<Output=T>>(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 00000000000..5d4ecbb5f81 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(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<T>(x: T, y: T) -> T; + fn simd_sub<T>(x: T, y: T) -> T; + fn simd_mul<T>(x: T, y: T) -> T; + fn simd_div<T>(x: T, y: T) -> T; + fn simd_shl<T>(x: T, y: T) -> T; + fn simd_shr<T>(x: T, y: T) -> T; + fn simd_and<T>(x: T, y: T) -> T; + fn simd_or<T>(x: T, y: T) -> T; + fn simd_xor<T>(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 00000000000..a20dd3ef72a --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(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<T, U>(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 00000000000..5802fb30bd6 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(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<T, U>(x: T, y: T) -> U; + fn simd_ne<T, U>(x: T, y: T) -> U; + fn simd_lt<T, U>(x: T, y: T) -> U; + fn simd_le<T, U>(x: T, y: T) -> U; + fn simd_gt<T, U>(x: T, y: T) -> U; + fn simd_ge<T, U>(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 00000000000..f0444c27170 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(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<T, E>(x: T, idx: u32, y: E) -> T; + fn simd_extract<T, E>(x: T, idx: u32) -> E; + + fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U; + fn simd_shuffle3<T, U>(x: T, y: T, idx: [u32; 3]) -> U; + fn simd_shuffle4<T, U>(x: T, y: T, idx: [u32; 4]) -> U; + fn simd_shuffle8<T, U>(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 fee4637f07f..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// 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<T>(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 025b2a77375..b8d7cd84141 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::<f32x8>(); } -#[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 540666f41ae..2883b80a25b 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, |
