From c8b6d5b23cc8b2d43ece9f06252c7e98280fb8e5 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 13 Jul 2015 11:35:00 -0700 Subject: [PATCH 01/40] Implement `repr(simd)` as an alias for `#[simd]`. --- src/librustc/middle/ty.rs | 5 +++-- src/librustc_trans/trans/adt.rs | 3 +++ src/librustc_typeck/check/mod.rs | 3 +++ src/libsyntax/attr.rs | 5 ++++- src/libsyntax/ext/deriving/generic/mod.rs | 2 +- src/libsyntax/feature_gate.rs | 20 +++++++++++++++++++ .../compile-fail/feature-gate-repr-simd.rs | 14 +++++++++++++ 7 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 src/test/compile-fail/feature-gate-repr-simd.rs diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 967eb3ff74f49..d7a58f4cdd08c 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3312,10 +3312,10 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> { variants: Vec>) -> Self { let mut flags = AdtFlags::NO_ADT_FLAGS; let attrs = tcx.get_attrs(did); - if attrs.iter().any(|item| item.check_name("fundamental")) { + if attr::contains_name(&attrs, "fundamental") { flags = flags | AdtFlags::IS_FUNDAMENTAL; } - if attrs.iter().any(|item| item.check_name("simd")) { + if tcx.lookup_simd(did) { flags = flags | AdtFlags::IS_SIMD; } if Some(did) == tcx.lang_items.phantom_data() { @@ -6116,6 +6116,7 @@ impl<'tcx> ctxt<'tcx> { /// Determine whether an item is annotated with `#[simd]` pub fn lookup_simd(&self, did: DefId) -> bool { self.has_attr(did, "simd") + || self.lookup_repr_hints(did).contains(&attr::ReprSimd) } /// Obtain the representation annotation for a struct definition. diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 326d1e2361e6d..0d34cce919a64 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -615,6 +615,9 @@ fn range_to_inttype(cx: &CrateContext, hint: Hint, bounds: &IntBounds) -> IntTyp attr::ReprPacked => { cx.tcx().sess.bug("range_to_inttype: found ReprPacked on an enum"); } + attr::ReprSimd => { + cx.tcx().sess.bug("range_to_inttype: found ReprSimd on an enum"); + } } for &ity in attempts { if bounds_usable(cx, ity, bounds) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bf5d1373d0bf5..e32964db7486a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4421,6 +4421,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"); } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 5e16465b4d4bf..3de9ba5197489 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -579,6 +579,7 @@ pub fn find_repr_attrs(diagnostic: &SpanHandler, attr: &Attribute) -> Vec Some(ReprExtern), "packed" => Some(ReprPacked), + "simd" => Some(ReprSimd), _ => match int_type_of_word(&word) { Some(ity) => Some(ReprInt(item.span, ity)), None => { @@ -628,6 +629,7 @@ pub enum ReprAttr { ReprInt(Span, IntType), ReprExtern, ReprPacked, + ReprSimd, } impl ReprAttr { @@ -636,7 +638,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/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 1f4860b7ec11e..f8f63e94ee574 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -739,7 +739,7 @@ fn find_repr_type_name(diagnostic: &SpanHandler, for a in type_attrs { for r in &attr::find_repr_attrs(diagnostic, a) { repr_type_name = match *r { - attr::ReprAny | attr::ReprPacked => continue, + attr::ReprAny | attr::ReprPacked | attr::ReprSimd => continue, attr::ReprExtern => "i32", attr::ReprInt(_, attr::SignedInt(ast::TyIs)) => "isize", diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 694a1a43f593d..a12291161f74f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -177,6 +177,9 @@ 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 + ("simd_basics", "1.3.0", Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -359,6 +362,7 @@ pub struct Features { pub allow_box: bool, pub allow_pushpop_unsafe: bool, pub simd_ffi: bool, + pub simd_basics: bool, pub unmarked_api: bool, pub negate_unsigned: bool, /// spans of #![feature] attrs for stable language features. for error reporting @@ -388,6 +392,7 @@ impl Features { allow_box: false, allow_pushpop_unsafe: false, simd_ffi: false, + simd_basics: false, unmarked_api: false, negate_unsigned: false, declared_stable_lang_features: Vec::new(), @@ -660,6 +665,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("simd_basics", i.span, + "SIMD types are experimental and possibly buggy"); + + } + } + } } } @@ -892,6 +911,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, allow_box: cx.has_feature("box_syntax"), allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"), simd_ffi: cx.has_feature("simd_ffi"), + simd_basics: cx.has_feature("simd_basics"), unmarked_api: cx.has_feature("unmarked_api"), negate_unsigned: cx.has_feature("negate_unsigned"), declared_stable_lang_features: accepted_features, diff --git a/src/test/compile-fail/feature-gate-repr-simd.rs b/src/test/compile-fail/feature-gate-repr-simd.rs new file mode 100644 index 0000000000000..fdafb2ad950c9 --- /dev/null +++ b/src/test/compile-fail/feature-gate-repr-simd.rs @@ -0,0 +1,14 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[repr(simd)] +struct Foo(u64, u64); //~ error: SIMD types are experimental + +fn main() {} From c66554cab3518a9f5c36eafd622ca4c8a3fda631 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 13 Jul 2015 11:57:46 -0700 Subject: [PATCH 02/40] switch core::simd to repr(simd) and deprecate it. This functionality will be available out of tree in the `simd` crate on crates.io. [breaking-change] --- src/libcore/lib.rs | 9 ++- src/libcore/simd.rs | 23 ++++--- src/libcore/simd_old.rs | 98 +++++++++++++++++++++++++++++ src/libstd/lib.rs | 1 + src/libstd/rt/unwind/seh64_gnu.rs | 1 - src/libstd/sys/windows/backtrace.rs | 2 + 6 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 src/libcore/simd_old.rs diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index ae85e2712ce81..c064d87e37026 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(simd_basics))] #![feature(staged_api)] #![feature(unboxed_closures)] @@ -150,7 +151,13 @@ pub mod iter; pub mod option; pub mod raw; pub mod result; + +#[cfg(stage0)] +#[path = "simd_old.rs"] +pub mod simd; +#[cfg(not(stage0))] pub mod simd; + pub mod slice; pub mod str; pub mod hash; diff --git a/src/libcore/simd.rs b/src/libcore/simd.rs index b06c0241093c3..d58d0c50a8982 100644 --- a/src/libcore/simd.rs +++ b/src/libcore/simd.rs @@ -37,11 +37,14 @@ #![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)] -#[simd] +#[repr(simd)] #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct i8x16(pub i8, pub i8, pub i8, pub i8, @@ -49,23 +52,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 +76,28 @@ 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); diff --git a/src/libcore/simd_old.rs b/src/libcore/simd_old.rs new file mode 100644 index 0000000000000..7ecd08bea3574 --- /dev/null +++ b/src/libcore/simd_old.rs @@ -0,0 +1,98 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! SIMD vectors. +//! +//! These types can be used for accessing basic SIMD operations. Each of them +//! implements the standard arithmetic operator traits (Add, Sub, Mul, Div, +//! Rem, Shl, Shr) through compiler magic, rather than explicitly. Currently +//! comparison operators are not implemented. To use SSE3+, you must enable +//! the features, like `-C target-feature=sse3,sse4.1,sse4.2`, or a more +//! specific `target-cpu`. No other SIMD intrinsics or high-level wrappers are +//! provided beyond this module. +//! +//! ```rust +//! # #![feature(core_simd)] +//! fn main() { +//! use std::simd::f32x4; +//! let a = f32x4(40.0, 41.0, 42.0, 43.0); +//! let b = f32x4(1.0, 1.1, 3.4, 9.8); +//! println!("{:?}", a + b); +//! } +//! ``` +//! +//! # Stability Note +//! +//! These are all experimental. The interface may change entirely, without +//! warning. + +#![unstable(feature = "core_simd", + reason = "needs an RFC to flesh out the design")] + +#![allow(non_camel_case_types)] +#![allow(missing_docs)] + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct i8x16(pub i8, pub i8, pub i8, pub i8, + pub i8, pub i8, pub i8, pub i8, + pub i8, pub i8, pub i8, pub i8, + pub i8, pub i8, pub i8, pub i8); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct i16x8(pub i16, pub i16, pub i16, pub i16, + pub i16, pub i16, pub i16, pub i16); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct i32x4(pub i32, pub i32, pub i32, pub i32); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct i64x2(pub i64, pub i64); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct u8x16(pub u8, pub u8, pub u8, pub u8, + pub u8, pub u8, pub u8, pub u8, + pub u8, pub u8, pub u8, pub u8, + pub u8, pub u8, pub u8, pub u8); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct u16x8(pub u16, pub u16, pub u16, pub u16, + pub u16, pub u16, pub u16, pub u16); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct u64x2(pub u64, pub u64); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[simd] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct f64x2(pub f64, pub f64); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 655fa04c2644e..bc7252fa33a86 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -294,6 +294,7 @@ pub use core::mem; pub use core::ops; pub use core::ptr; pub use core::raw; +#[allow(deprecated)] pub use core::simd; pub use core::result; pub use core::option; diff --git a/src/libstd/rt/unwind/seh64_gnu.rs b/src/libstd/rt/unwind/seh64_gnu.rs index 847ba47ff7251..78f969bfbeb5b 100644 --- a/src/libstd/rt/unwind/seh64_gnu.rs +++ b/src/libstd/rt/unwind/seh64_gnu.rs @@ -21,7 +21,6 @@ use self::EXCEPTION_DISPOSITION::*; use rt::dwarf::eh; use core::mem; use core::ptr; -use simd; use libc::{c_void, c_ulonglong, DWORD, LPVOID}; type ULONG_PTR = c_ulonglong; diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index 7078ee92085fb..d36ca709c5c94 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -194,6 +194,8 @@ mod arch { #[cfg(target_arch = "x86_64")] mod arch { + #![allow(deprecated)] + use libc::{c_longlong, c_ulonglong}; use libc::types::os::arch::extra::{WORD, DWORD, DWORDLONG}; use simd; From e364f0eb5a51a96932ecd01dd2319eff4bdae2d1 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 13 Jul 2015 17:10:44 -0700 Subject: [PATCH 03/40] feature gate `cfg(target_feature)`. This is theoretically a breaking change, but GitHub search turns up no uses of it, and most non-built-in cfg's are passed via cargo features, which look like `feature = "..."`, and hence can't overlap. --- src/librustc_driver/driver.rs | 19 +++++- src/libsyntax/attr.rs | 15 +++-- src/libsyntax/config.rs | 28 ++++++--- src/libsyntax/ext/base.rs | 6 +- src/libsyntax/ext/cfg.rs | 3 +- src/libsyntax/ext/expand.rs | 14 +++-- src/libsyntax/feature_gate.rs | 60 +++++++++++++++++++ src/libsyntax/test.rs | 4 +- .../feature-gate-cfg-target-feature.rs | 21 +++++++ src/test/run-fail-fulldeps/qquote.rs | 4 +- src/test/run-pass-fulldeps/qquote.rs | 4 +- 11 files changed, 150 insertions(+), 28 deletions(-) create mode 100644 src/test/compile-fail/feature-gate-cfg-target-feature.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 263a8e1480702..346e7a7bf9886 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -406,8 +406,10 @@ pub fn phase_2_configure_and_expand(sess: &Session, // // baz! should not use this definition unless foo is enabled. - krate = time(time_passes, "configuration 1", move || - syntax::config::strip_unconfigured_items(sess.diagnostic(), krate)); + let mut feature_gated_cfgs = vec![]; + krate = time(time_passes, "configuration 1", || + syntax::config::strip_unconfigured_items(sess.diagnostic(), krate, + &mut feature_gated_cfgs)); *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs); @@ -511,6 +513,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, cfg, macros, syntax_exts, + &mut feature_gated_cfgs, krate); if cfg!(windows) { env::set_var("PATH", &_old_path); @@ -536,7 +539,17 @@ pub fn phase_2_configure_and_expand(sess: &Session, // strip again, in case expansion added anything with a #[cfg]. krate = time(time_passes, "configuration 2", || - syntax::config::strip_unconfigured_items(sess.diagnostic(), krate)); + syntax::config::strip_unconfigured_items(sess.diagnostic(), krate, + &mut feature_gated_cfgs)); + + time(time_passes, "gated configuration checking", || { + let features = sess.features.borrow(); + feature_gated_cfgs.sort(); + feature_gated_cfgs.dedup(); + for cfg in &feature_gated_cfgs { + cfg.check_and_emit(sess.diagnostic(), &features); + } + }); krate = time(time_passes, "maybe building test harness", || syntax::test::modify_for_testing(&sess.parse_sess, diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 3de9ba5197489..7540c2ff831e9 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -19,6 +19,7 @@ use ast::{AttrId, Attribute, Attribute_, MetaItem, MetaWord, MetaNameValue, Meta use codemap::{Span, Spanned, spanned, dummy_spanned}; use codemap::BytePos; use diagnostic::SpanHandler; +use feature_gate::GatedCfg; use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use parse::token::{InternedString, intern_and_get_ident}; use parse::token; @@ -357,24 +358,28 @@ pub fn requests_inline(attrs: &[Attribute]) -> bool { } /// Tests if a cfg-pattern matches the cfg set -pub fn cfg_matches(diagnostic: &SpanHandler, cfgs: &[P], cfg: &ast::MetaItem) -> bool { +pub fn cfg_matches(diagnostic: &SpanHandler, cfgs: &[P], cfg: &ast::MetaItem, + feature_gated_cfgs: &mut Vec) -> bool { match cfg.node { ast::MetaList(ref pred, ref mis) if &pred[..] == "any" => - mis.iter().any(|mi| cfg_matches(diagnostic, cfgs, &**mi)), + mis.iter().any(|mi| cfg_matches(diagnostic, cfgs, &**mi, feature_gated_cfgs)), ast::MetaList(ref pred, ref mis) if &pred[..] == "all" => - mis.iter().all(|mi| cfg_matches(diagnostic, cfgs, &**mi)), + mis.iter().all(|mi| cfg_matches(diagnostic, cfgs, &**mi, feature_gated_cfgs)), ast::MetaList(ref pred, ref mis) if &pred[..] == "not" => { if mis.len() != 1 { diagnostic.span_err(cfg.span, "expected 1 cfg-pattern"); return false; } - !cfg_matches(diagnostic, cfgs, &*mis[0]) + !cfg_matches(diagnostic, cfgs, &*mis[0], feature_gated_cfgs) } ast::MetaList(ref pred, _) => { diagnostic.span_err(cfg.span, &format!("invalid predicate `{}`", pred)); false }, - ast::MetaWord(_) | ast::MetaNameValue(..) => contains(cfgs, cfg), + ast::MetaWord(_) | ast::MetaNameValue(..) => { + feature_gated_cfgs.extend(GatedCfg::gate(cfg)); + contains(cfgs, cfg) + } } } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 366806bc19b49..faf0b51c8de0e 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -10,6 +10,7 @@ use attr::AttrMetaMethods; use diagnostic::SpanHandler; +use feature_gate::GatedCfg; use fold::Folder; use {ast, fold, attr}; use codemap::{Spanned, respan}; @@ -25,10 +26,13 @@ struct Context where F: FnMut(&[ast::Attribute]) -> bool { // Support conditional compilation by transforming the AST, stripping out // any items that do not belong in the current configuration -pub fn strip_unconfigured_items(diagnostic: &SpanHandler, krate: ast::Crate) -> ast::Crate { - let krate = process_cfg_attr(diagnostic, krate); +pub fn strip_unconfigured_items(diagnostic: &SpanHandler, krate: ast::Crate, + feature_gated_cfgs: &mut Vec) + -> ast::Crate +{ + let krate = process_cfg_attr(diagnostic, krate, feature_gated_cfgs); let config = krate.config.clone(); - strip_items(krate, |attrs| in_cfg(diagnostic, &config, attrs)) + strip_items(krate, |attrs| in_cfg(diagnostic, &config, attrs, feature_gated_cfgs)) } impl fold::Folder for Context where F: FnMut(&[ast::Attribute]) -> bool { @@ -248,7 +252,8 @@ fn foreign_item_in_cfg(cx: &mut Context, item: &ast::ForeignItem) -> bool // Determine if an item should be translated in the current crate // configuration based on the item's attributes -fn in_cfg(diagnostic: &SpanHandler, cfg: &[P], attrs: &[ast::Attribute]) -> bool { +fn in_cfg(diagnostic: &SpanHandler, cfg: &[P], attrs: &[ast::Attribute], + feature_gated_cfgs: &mut Vec) -> bool { attrs.iter().all(|attr| { let mis = match attr.node.value.node { ast::MetaList(_, ref mis) if attr.check_name("cfg") => mis, @@ -260,25 +265,29 @@ fn in_cfg(diagnostic: &SpanHandler, cfg: &[P], attrs: &[ast::Attr return true; } - attr::cfg_matches(diagnostic, cfg, &*mis[0]) + attr::cfg_matches(diagnostic, cfg, &*mis[0], + feature_gated_cfgs) }) } -struct CfgAttrFolder<'a> { +struct CfgAttrFolder<'a, 'b> { diag: &'a SpanHandler, config: ast::CrateConfig, + feature_gated_cfgs: &'b mut Vec } // Process `#[cfg_attr]`. -fn process_cfg_attr(diagnostic: &SpanHandler, krate: ast::Crate) -> ast::Crate { +fn process_cfg_attr(diagnostic: &SpanHandler, krate: ast::Crate, + feature_gated_cfgs: &mut Vec) -> ast::Crate { let mut fld = CfgAttrFolder { diag: diagnostic, config: krate.config.clone(), + feature_gated_cfgs: feature_gated_cfgs, }; fld.fold_crate(krate) } -impl<'a> fold::Folder for CfgAttrFolder<'a> { +impl<'a,'b> fold::Folder for CfgAttrFolder<'a,'b> { fn fold_attribute(&mut self, attr: ast::Attribute) -> Option { if !attr.check_name("cfg_attr") { return fold::noop_fold_attribute(attr, self); @@ -299,7 +308,8 @@ impl<'a> fold::Folder for CfgAttrFolder<'a> { } }; - if attr::cfg_matches(self.diag, &self.config[..], &cfg) { + if attr::cfg_matches(self.diag, &self.config[..], &cfg, + self.feature_gated_cfgs) { Some(respan(mi.span, ast::Attribute_ { id: attr::mk_attr_id(), style: attr.node.style, diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index d4b5e67eeb492..ef11a2bd66e80 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -17,6 +17,7 @@ use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION, CompilerExpansion}; use ext; use ext::expand; use ext::tt::macro_rules; +use feature_gate::GatedCfg; use parse; use parse::parser; use parse::token; @@ -632,6 +633,7 @@ pub struct ExtCtxt<'a> { pub backtrace: ExpnId, pub ecfg: expand::ExpansionConfig<'a>, pub crate_root: Option<&'static str>, + pub feature_gated_cfgs: &'a mut Vec, pub mod_path: Vec , pub exported_macros: Vec, @@ -642,7 +644,8 @@ pub struct ExtCtxt<'a> { impl<'a> ExtCtxt<'a> { pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig, - ecfg: expand::ExpansionConfig<'a>) -> ExtCtxt<'a> { + ecfg: expand::ExpansionConfig<'a>, + feature_gated_cfgs: &'a mut Vec) -> ExtCtxt<'a> { let env = initial_syntax_expander_table(&ecfg); ExtCtxt { parse_sess: parse_sess, @@ -651,6 +654,7 @@ impl<'a> ExtCtxt<'a> { mod_path: Vec::new(), ecfg: ecfg, crate_root: None, + feature_gated_cfgs: feature_gated_cfgs, exported_macros: Vec::new(), syntax_env: env, recursion_count: 0, diff --git a/src/libsyntax/ext/cfg.rs b/src/libsyntax/ext/cfg.rs index 8af7fb7b268af..aa654e30530af 100644 --- a/src/libsyntax/ext/cfg.rs +++ b/src/libsyntax/ext/cfg.rs @@ -34,6 +34,7 @@ pub fn expand_cfg<'cx>(cx: &mut ExtCtxt, return DummyResult::expr(sp); } - let matches_cfg = attr::cfg_matches(&cx.parse_sess.span_diagnostic, &cx.cfg, &*cfg); + let matches_cfg = attr::cfg_matches(&cx.parse_sess.span_diagnostic, &cx.cfg, &*cfg, + cx.feature_gated_cfgs); MacEager::expr(cx.expr_bool(sp, matches_cfg)) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index e61a0b5401efd..4f89b3494d403 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -21,7 +21,7 @@ use attr::AttrMetaMethods; use codemap; use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute, CompilerExpansion}; use ext::base::*; -use feature_gate::{self, Features}; +use feature_gate::{self, Features, GatedCfg}; use fold; use fold::*; use parse; @@ -1687,8 +1687,10 @@ pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess, // these are the macros being imported to this crate: imported_macros: Vec, user_exts: Vec, + feature_gated_cfgs: &mut Vec, c: Crate) -> Crate { - let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg); + let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg, + feature_gated_cfgs); if std_inject::no_core(&c) { cx.crate_root = None; } else if std_inject::no_std(&c) { @@ -1878,7 +1880,7 @@ mod tests { src, Vec::new(), &sess); // should fail: - expand_crate(&sess,test_ecfg(),vec!(),vec!(),crate_ast); + expand_crate(&sess,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast); } // make sure that macros can't escape modules @@ -1891,7 +1893,7 @@ mod tests { "".to_string(), src, Vec::new(), &sess); - expand_crate(&sess,test_ecfg(),vec!(),vec!(),crate_ast); + expand_crate(&sess,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast); } // macro_use modules should allow macros to escape @@ -1903,14 +1905,14 @@ mod tests { "".to_string(), src, Vec::new(), &sess); - expand_crate(&sess, test_ecfg(), vec!(), vec!(), crate_ast); + expand_crate(&sess, test_ecfg(), vec!(), vec!(), &mut vec![], crate_ast); } fn expand_crate_str(crate_str: String) -> ast::Crate { let ps = parse::ParseSess::new(); let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod()); // the cfg argument actually does matter, here... - expand_crate(&ps,test_ecfg(),vec!(),vec!(),crate_ast) + expand_crate(&ps,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast) } // find the pat_ident paths in a crate diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index a12291161f74f..9a1c97a4d29f5 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'. @@ -180,6 +181,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ // allow `repr(simd)`, and importing the various simd intrinsics ("simd_basics", "1.3.0", Active), + + // Allows cfg(target_feature = "..."). + ("cfg_target_feature", "1.3.0", Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -327,6 +331,59 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ ("recursion_limit", CrateLevel), ]; +macro_rules! cfg_fn { + (|$x: ident| $e: expr) => {{ + fn f($x: &Features) -> bool { + $e + } + f as fn(&Features) -> bool + }} +} +// cfg(...)'s that are feature gated +const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[ + // (name in cfg, feature, function to check if the feature is enabled) + ("target_feature", "cfg_target_feature", cfg_fn!(|x| x.cfg_target_feature)), +]; + +#[derive(Debug, Eq, PartialEq)] +pub struct GatedCfg { + span: Span, + index: usize, +} +impl Ord for GatedCfg { + fn cmp(&self, other: &GatedCfg) -> cmp::Ordering { + (self.span.lo.0, self.span.hi.0, self.index) + .cmp(&(other.span.lo.0, other.span.hi.0, other.index)) + } +} +impl PartialOrd for GatedCfg { + fn partial_cmp(&self, other: &GatedCfg) -> Option { + Some(self.cmp(other)) + } +} + +impl GatedCfg { + pub fn gate(cfg: &ast::MetaItem) -> Option { + let name = cfg.name(); + GATED_CFGS.iter() + .position(|info| info.0 == name) + .map(|idx| { + GatedCfg { + span: cfg.span, + index: idx + } + }) + } + pub fn check_and_emit(&self, diagnostic: &SpanHandler, features: &Features) { + let (cfg, feature, has_feature) = GATED_CFGS[self.index]; + if !has_feature(features) { + let explain = format!("`cfg({})` is experimental and subject to change", cfg); + emit_feature_err(diagnostic, feature, self.span, &explain); + } + } +} + + #[derive(PartialEq, Copy, Clone, Debug)] pub enum AttributeType { /// Normal, builtin attribute that is consumed @@ -373,6 +430,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 { @@ -401,6 +459,7 @@ impl Features { static_recursion: false, default_type_parameter_fallback: false, type_macros: false, + cfg_target_feature: false, } } } @@ -920,6 +979,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, static_recursion: cx.has_feature("static_recursion"), default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"), type_macros: cx.has_feature("type_macros"), + cfg_target_feature: cx.has_feature("cfg_target_feature"), } } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index ea99291d6c291..26fb287ce35d1 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -246,11 +246,13 @@ fn generate_test_harness(sess: &ParseSess, krate: ast::Crate, cfg: &ast::CrateConfig, sd: &diagnostic::SpanHandler) -> ast::Crate { + let mut feature_gated_cfgs = vec![]; let mut cx: TestCtxt = TestCtxt { sess: sess, span_diagnostic: sd, ext_cx: ExtCtxt::new(sess, cfg.clone(), - ExpansionConfig::default("test".to_string())), + ExpansionConfig::default("test".to_string()), + &mut feature_gated_cfgs), path: Vec::new(), testfns: Vec::new(), reexport_test_harness_main: reexport_test_harness_main, diff --git a/src/test/compile-fail/feature-gate-cfg-target-feature.rs b/src/test/compile-fail/feature-gate-cfg-target-feature.rs new file mode 100644 index 0000000000000..7832e1c7c5152 --- /dev/null +++ b/src/test/compile-fail/feature-gate-cfg-target-feature.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[cfg(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); + +#[cfg(not(any(all(target_feature = "x"))))] //~ ERROR `cfg(target_feature)` is experimental +fn foo() {} + +fn main() { + cfg!(target_feature = "x"); + //~^ ERROR `cfg(target_feature)` is experimental and subject to change +} diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs index 4251579bbdcd1..eac38037b4bc1 100644 --- a/src/test/run-fail-fulldeps/qquote.rs +++ b/src/test/run-fail-fulldeps/qquote.rs @@ -23,9 +23,11 @@ use syntax::print::pprust; fn main() { let ps = syntax::parse::ParseSess::new(); + let mut feature_gated_cfgs = vec![]; let mut cx = syntax::ext::base::ExtCtxt::new( &ps, vec![], - syntax::ext::expand::ExpansionConfig::default("qquote".to_string())); + syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), + &mut feature_gated_cfgs); cx.bt_push(syntax::codemap::ExpnInfo { call_site: DUMMY_SP, callee: syntax::codemap::NameAndSpan { diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index 6670f200ba71e..e272a5fe4f6cd 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -19,9 +19,11 @@ use syntax::print::pprust::*; fn main() { let ps = syntax::parse::ParseSess::new(); + let mut feature_gated_cfgs = vec![]; let mut cx = syntax::ext::base::ExtCtxt::new( &ps, vec![], - syntax::ext::expand::ExpansionConfig::default("qquote".to_string())); + syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), + &mut feature_gated_cfgs); cx.bt_push(syntax::codemap::ExpnInfo { call_site: DUMMY_SP, callee: syntax::codemap::NameAndSpan { From 4f4425840dac441e1050319893882177d040c4f3 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Tue, 14 Jul 2015 15:49:03 -0700 Subject: [PATCH 04/40] Add some SIMD target_feature cfg's when appropriate. NB. this may not be 100% perfect. --- src/librustc_driver/lib.rs | 4 +- src/librustc_driver/target_features.rs | 98 ++++++++++++++++++++++++++ src/librustdoc/core.rs | 5 +- 3 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 src/librustc_driver/target_features.rs diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 1d440af269713..60eaffd71cbc6 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -89,6 +89,7 @@ pub mod test; pub mod driver; pub mod pretty; +pub mod target_features; const BUG_REPORT_URL: &'static str = @@ -136,7 +137,8 @@ pub fn run_compiler<'a>(args: &[String], if sess.unstable_options() { sess.opts.show_span = matches.opt_str("show-span"); } - let cfg = config::build_configuration(&sess); + let mut cfg = config::build_configuration(&sess); + target_features::add_configuration(&mut cfg, &sess); do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile)); diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs new file mode 100644 index 0000000000000..ca76046acf0fb --- /dev/null +++ b/src/librustc_driver/target_features.rs @@ -0,0 +1,98 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::{ast, attr}; +use rustc::session::Session; +use syntax::parse::token::InternedString; +use syntax::parse::token::intern_and_get_ident as intern; + +/// Add `target_feature = "..."` cfgs for a variety of platform +/// specific features (SSE, NEON etc.). +/// +/// This uses a scheme similar to that employed by clang: reimplement +/// the target feature knowledge. *Theoretically* we could query LLVM +/// since that has perfect knowledge about what things are enabled in +/// code-generation, however, it is extremely non-obvious how to do +/// this successfully. Each platform defines a subclass of a +/// SubtargetInfo, which knows all this information, but the ways to +/// query them do not seem to be public. +pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) { + let tf = InternedString::new("target_feature"); + macro_rules! fillout { + ($($func: ident, $name: expr;)*) => {{ + $(if $func(sess) { + cfg.push(attr::mk_name_value_item_str(tf.clone(), intern($name))) + })* + }} + } + fillout! { + has_sse, "sse"; + has_sse2, "sse2"; + has_sse3, "sse3"; + has_ssse3, "ssse3"; + has_sse41, "sse4.1"; + has_sse42, "sse4.2"; + has_avx, "avx"; + has_avx2, "avx2"; + has_neon, "neon"; + has_vfp, "vfp"; + } +} + + +fn features_contain(sess: &Session, s: &str) -> bool { + sess.target.target.options.features.contains(s) || + sess.opts.cg.target_feature.contains(s) +} + +pub fn has_sse(sess: &Session) -> bool { + features_contain(sess, "+sse") || + has_sse2(sess) +} +pub fn has_sse2(sess: &Session) -> bool { + // x86-64 requires at least SSE2 support + sess.target.target.arch == "x86_64" || + features_contain(sess, "+sse2") || + has_sse3(sess) +} +pub fn has_sse3(sess: &Session) -> bool { + features_contain(sess, "+sse3") || + has_ssse3(sess) +} +pub fn has_ssse3(sess: &Session) -> bool { + features_contain(sess, "+ssse3") || + has_sse41(sess) +} +pub fn has_sse41(sess: &Session) -> bool { + features_contain(sess, "+sse4.1") || + has_sse42(sess) +} +pub fn has_sse42(sess: &Session) -> bool { + features_contain(sess, "+sse4.2") || + has_avx(sess) +} +pub fn has_avx(sess: &Session) -> bool { + features_contain(sess, "+avx") || + has_avx2(sess) +} +pub fn has_avx2(sess: &Session) -> bool { + features_contain(sess, "+avx2") +} + +pub fn has_neon(sess: &Session) -> bool { + // AArch64 requires NEON support + sess.target.target.arch == "aarch64" || + features_contain(sess, "+neon") +} +pub fn has_vfp(sess: &Session) -> bool { + // AArch64 requires VFP support + sess.target.target.arch == "aarch64" || + features_contain(sess, "+vfp") +} diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index ba9caa2f3f356..81399938f27c5 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -10,7 +10,7 @@ pub use self::MaybeTyped::*; use rustc_lint; -use rustc_driver::driver; +use rustc_driver::{driver, target_features}; use rustc::session::{self, config}; use rustc::middle::{privacy, ty}; use rustc::ast_map; @@ -119,7 +119,8 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: Externs, span_diagnostic_handler); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - let cfg = config::build_configuration(&sess); + let mut cfg = config::build_configuration(&sess); + target_features::add_configuration(&mut cfg, &sess); let krate = driver::phase_1_parse_input(&sess, cfg, &input); From 1bfbde6778ee4839ca62aad3d025477296cf323f Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 16 Jul 2015 11:59:23 -0700 Subject: [PATCH 05/40] Add comparison and shuffle SIMD intrinsics. - simd_eq, simd_ne, simd_lt, simd_le, simd_gt, simd_ge - simd_shuffleNNN --- src/librustc_trans/trans/base.rs | 11 +-- src/librustc_trans/trans/expr.rs | 2 +- src/librustc_trans/trans/intrinsic.rs | 132 +++++++++++++++++++++++++- src/librustc_typeck/check/mod.rs | 27 +++++- src/librustc_typeck/diagnostics.rs | 3 +- 5 files changed, 163 insertions(+), 12 deletions(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 1982f04195f0b..c6944e7b75659 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -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. diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index c5043f867ded0..9ba45e0d481a3 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -1797,7 +1797,7 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } ast::BiEq | ast::BiNe | ast::BiLt | ast::BiGe | ast::BiLe | ast::BiGt => { if is_simd { - base::compare_simd_types(bcx, lhs, rhs, intype, op.node, binop_debug_loc) + base::compare_simd_types(bcx, lhs, rhs, intype, val_ty(lhs), op.node, binop_debug_loc) } else { base::compare_scalar_types(bcx, lhs, rhs, intype, op.node, binop_debug_loc) } diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 33e5d814eb186..489c54dc6e2d2 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -800,7 +800,15 @@ 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, + &llargs, + ret_ty, llret_ty, + call_debug_location, + call_info) + } // This requires that atomic intrinsics follow a specific naming pattern: // "atomic_[_]", and no ordering means SeqCst (_, name) if name.starts_with("atomic_") => { @@ -1263,3 +1271,125 @@ 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>(bcx: Block<'blk, 'tcx>, + name: &str, + _substs: subst::Substs<'tcx>, + callee_ty: Ty<'tcx>, + llargs: &[ValueRef], + ret_ty: Ty<'tcx>, + llret_ty: Type, + call_debug_location: DebugLoc, + call_info: NodeIdAndSpan) -> ValueRef { + 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!() + }; + + 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 + }; + + macro_rules! require { + ($cond: expr, $($fmt: tt)*) => { + if !$cond { + bcx.sess().span_err(call_info.span, &format!($($fmt)*)); + return C_null(llret_ty) + } + } + } + + if let Some(cmp_op) = comparison { + assert_eq!(arg_tys.len(), 2); + // we need nominal equality here, not LLVM (structural) + // equality + require!(arg_tys[0] == arg_tys[1], + "SIMD comparison intrinsic monomorphised with different input types"); + require!(arg_tys[0].is_simd(tcx), + "SIMD comparison intrinsic monomorphised for non-SIMD argument type"); + require!(ret_ty.is_simd(tcx), + "SIMD comparison intrinsic monomorphised for non-SIMD return type"); + + let in_len = arg_tys[0].simd_size(tcx); + let out_len = ret_ty.simd_size(tcx); + require!(in_len == out_len, + "SIMD comparison intrinsic monomorphised for non-SIMD argument type"); + require!(llret_ty.element_type().kind() == llvm::Integer, + "SIMD comparison intrinsic monomorphised with non-integer return"); + + return compare_simd_types(bcx, + llargs[0], + llargs[1], + arg_tys[0].simd_type(tcx), + 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?") + }; + assert_eq!(llargs.len(), 2 + n); + + require!(arg_tys[0] == arg_tys[1], + "SIMD shuffle intrinsic monomorphised with different input types"); + require!(ret_ty.is_simd(tcx), + "SIMD shuffle intrinsic monomorphised for non-SIMD return type"); + + let in_len = arg_tys[0].simd_size(tcx); + let out_len = ret_ty.simd_size(tcx); + require!(out_len == n, + "SIMD shuffle intrinsic monomorphised with return type of length {} (expected {})", + out_len, n); + require!(arg_tys[0].simd_type(tcx) == ret_ty.simd_type(tcx), + "SIMD shuffle intrinsic monomorphised with different \ + input and return element types"); + + let total_len = in_len as u64 * 2; + + let indices: Option> = llargs[2..] + .iter() + .enumerate() + .map(|(i, val)| { + let arg_idx = i + 2; + let c = const_to_opt_uint(*val); + match c { + None => { + bcx.sess().span_err(call_info.span, + &format!("SIMD shuffle intrinsic argument #{} \ + is not a constant", + arg_idx)); + None + } + Some(idx) if idx >= total_len => { + bcx.sess().span_err(call_info.span, + &format!("SIMD shuffle intrinsic argument #{} \ + 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)) + } + C_null(llret_ty) +} diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e32964db7486a..749bc8ab2942b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -110,6 +110,7 @@ use util::lev_distance::lev_distance; use std::cell::{Cell, Ref, RefCell}; use std::collections::HashSet; +use std::iter; use std::mem::replace; use std::slice; use syntax::{self, abi, attr}; @@ -5091,6 +5092,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { let tcx = ccx.tcx; let name = it.ident.name.as_str(); + let mut infer_ctxt = None; 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"); @@ -5338,7 +5340,28 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { "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), + param(ccx, 0))], tcx.types.u64), + "simd_eq" | "simd_ne" | "simd_lt" | "simd_le" | "simd_gt" | "simd_ge" => { + (2, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 1)) + } + name if name.starts_with("simd_shuffle") => { + match name["simd_shuffle".len()..].parse() { + Ok(n) => { + let mut params = vec![param(ccx, 0), param(ccx, 0)]; + params.extend(iter::repeat(tcx.types.u32).take(n)); + + let ictxt = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); + let ret = ictxt.next_ty_var(); + infer_ctxt = Some(ictxt); + (2, params, ret) + } + Err(_) => { + span_err!(tcx.sess, it.span, E0439, + "invalid `simd_shuffle`, needs length: `{}`", name); + return + } + } + } "try" => { let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8); @@ -5381,7 +5404,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { i_n_tps, n_tps); } else { require_same_types(tcx, - None, + infer_ctxt.as_ref(), false, it.span, i_ty.ty, diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 62804426df69f..093ffc6a9963e 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -2800,5 +2800,6 @@ 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: `{}` } From 9af385bddb3076637ab299672c90702562644894 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 16 Jul 2015 16:46:36 -0700 Subject: [PATCH 06/40] Add rustc_platform_intrinsics & some arm/x86 intrs. These are enough to implement a cross-platform SIMD single-precision mandelbrot renderer. --- mk/crates.mk | 5 +- src/librustc_platform_intrinsics/aarch64.rs | 49 +++++++++++ src/librustc_platform_intrinsics/arm.rs | 46 ++++++++++ src/librustc_platform_intrinsics/lib.rs | 94 +++++++++++++++++++++ src/librustc_platform_intrinsics/x86.rs | 38 +++++++++ src/librustc_trans/lib.rs | 1 + src/librustc_trans/trans/intrinsic.rs | 37 +++++++- src/librustc_typeck/check/mod.rs | 6 ++ 8 files changed, 273 insertions(+), 3 deletions(-) create mode 100644 src/librustc_platform_intrinsics/aarch64.rs create mode 100644 src/librustc_platform_intrinsics/arm.rs create mode 100755 src/librustc_platform_intrinsics/lib.rs create mode 100644 src/librustc_platform_intrinsics/x86.rs diff --git a/mk/crates.mk b/mk/crates.mk index af2a663b61ded..611f0146285e4 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,7 +74,7 @@ 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 + log syntax serialize rustc_llvm rustc_platform_intrinsics DEPS_rustc_typeck := rustc syntax DEPS_rustc_borrowck := rustc log graphviz syntax DEPS_rustc_resolve := 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/librustc_platform_intrinsics/aarch64.rs b/src/librustc_platform_intrinsics/aarch64.rs new file mode 100644 index 0000000000000..2bdb9ce4327bc --- /dev/null +++ b/src/librustc_platform_intrinsics/aarch64.rs @@ -0,0 +1,49 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use {Intrinsic, i, f, v}; +use rustc::middle::ty; + +macro_rules! p { + ($name: expr, ($($inputs: tt),*) -> $output: tt) => { + plain!(concat!("llvm.aarch64.neon.", $name), ($($inputs),*) -> $output) + } +} +pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { + Some(match name { + "vmaxvq_u8" => p!("umaxv.i8.v16i8", (i8x16) -> i8), + "vmaxvq_u16" => p!("umaxv.i16.v8i16", (i16x8) -> i16), + "vmaxvq_u32" => p!("umaxv.i32.v4i32", (i32x4) -> i32), + + "vmaxvq_s8" => p!("smaxv.i8.v16i8", (i8x16) -> i8), + "vmaxvq_s16" => p!("smaxv.i16.v8i16", (i16x8) -> i16), + "vmaxvq_s32" => p!("smaxv.i32.v4i32", (i32x4) -> i32), + + "vminvq_u8" => p!("uminv.i8.v16i8", (i8x16) -> i8), + "vminvq_u16" => p!("uminv.i16.v8i16", (i16x8) -> i16), + "vminvq_u32" => p!("uminv.i32.v4i32", (i32x4) -> i32), + "vminvq_s8" => p!("sminv.i8.v16i8", (i8x16) -> i8), + "vminvq_s16" => p!("sminv.i16.v8i16", (i16x8) -> i16), + "vminvq_s32" => p!("sminv.i32.v4i32", (i32x4) -> i32), + + "vsqrtq_f32" => plain!("llvm.sqrt.v4f32", (f32x4) -> f32x4), + "vsqrtq_f64" => plain!("llvm.sqrt.v2f64", (f64x2) -> f64x2), + + "vrsqrteq_f32" => p!("vrsqrte.v4f32", (f32x4) -> f32x4), + "vrsqrteq_f64" => p!("vrsqrte.v2f64", (f64x2) -> f64x2), + + "vmaxq_f32" => p!("fmax.v4f32", (f32x4, f32x4) -> f32x4), + "vmaxq_f64" => p!("fmax.v2f64", (f64x2, f64x2) -> f64x2), + + "vminq_f32" => p!("fmin.v4f32", (f32x4, f32x4) -> f32x4), + "vminq_f64" => p!("fmin.v2f64", (f64x2, f64x2) -> f64x2), + _ => return None, + }) +} diff --git a/src/librustc_platform_intrinsics/arm.rs b/src/librustc_platform_intrinsics/arm.rs new file mode 100644 index 0000000000000..7fa7d45a600f5 --- /dev/null +++ b/src/librustc_platform_intrinsics/arm.rs @@ -0,0 +1,46 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use {Intrinsic, i, f, v}; +use rustc::middle::ty; + +macro_rules! p { + ($name: expr, ($($inputs: tt),*) -> $output: tt) => { + plain!(concat!("llvm.arm.neon.", $name), ($($inputs),*) -> $output) + } +} +pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { + Some(match name { + "vpmax_u8" => p!("vpmaxu.v8i8", (i8x8, i8x8) -> i8x8), + "vpmax_s8" => p!("vpmaxs.v8i8", (i8x8, i8x8) -> i8x8), + "vpmax_u16" => p!("vpmaxu.v4i16", (i16x4, i16x4) -> i16x4), + "vpmax_s16" => p!("vpmaxs.v4i16", (i16x4, i16x4) -> i16x4), + "vpmax_u32" => p!("vpmaxu.v2i32", (i32x2, i32x2) -> i32x2), + "vpmax_s32" => p!("vpmaxs.v2i32", (i32x2, i32x2) -> i32x2), + + "vpmin_u8" => p!("vpminu.v8i8", (i8x8, i8x8) -> i8x8), + "vpmin_s8" => p!("vpmins.v8i8", (i8x8, i8x8) -> i8x8), + "vpmin_u16" => p!("vpminu.v4i16", (i16x4, i16x4) -> i16x4), + "vpmin_s16" => p!("vpmins.v4i16", (i16x4, i16x4) -> i16x4), + "vpmin_u32" => p!("vpminu.v2i32", (i32x2, i32x2) -> i32x2), + "vpmin_s32" => p!("vpmins.v2i32", (i32x2, i32x2) -> i32x2), + + "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), + + "vmaxq_f32" => p!("vmaxs.v4f32", (f32x4, f32x4) -> f32x4), + + "vminq_f32" => p!("vmins.v4f32", (f32x4, f32x4) -> f32x4), + _ => return None, + }) +} diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs new file mode 100755 index 0000000000000..17e98770e835b --- /dev/null +++ b/src/librustc_platform_intrinsics/lib.rs @@ -0,0 +1,94 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg_attr(stage0, feature(custom_attribute))] +#![crate_name = "rustc_platform_intrinsics"] +#![unstable(feature = "rustc_private", issue = "27812")] +#![staged_api] +#![crate_type = "dylib"] +#![crate_type = "rlib"] +#![feature(staged_api, rustc_private)] + +extern crate rustc_llvm as llvm; +extern crate rustc; + +use rustc::middle::ty; + +pub struct Intrinsic { + pub inputs: Vec, + pub output: Type, + + pub definition: IntrinsicDef, +} + +#[derive(Clone)] +pub enum Type { + Integer(u8), + Float(u8), + Pointer(Box), + Vector(Box, u8), +} + +pub enum IntrinsicDef { + Named(&'static str), +} + +fn i(width: u8) -> Type { Type::Integer(width) } +fn f(width: u8) -> Type { Type::Float(width) } +fn v(x: Type, length: u8) -> Type { Type::Vector(Box::new(x), length) } + +macro_rules! ty { + (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)); + + (i64) => (i(64)); + (i32) => (i(32)); + (i16) => (i(16)); + (i8) => (i(8)); + (f32) => (f(32)); + (f64) => (f(64)); +} +macro_rules! plain { + ($name: expr, ($($inputs: tt),*) -> $output: tt) => { + Intrinsic { + inputs: vec![$(ty!($inputs)),*], + output: ty!($output), + definition: ::IntrinsicDef::Named($name) + } + } +} + +mod x86; +mod arm; +mod aarch64; + +impl Intrinsic { + pub fn find<'tcx>(tcx: &ty::ctxt<'tcx>, name: &str) -> Option { + if name.starts_with("x86_") { + x86::find(tcx, &name["x86_".len()..]) + } else if name.starts_with("arm_") { + arm::find(tcx, &name["arm_".len()..]) + } else if name.starts_with("aarch64_") { + aarch64::find(tcx, &name["aarch64_".len()..]) + } else { + None + } + } +} diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs new file mode 100644 index 0000000000000..93cadf8b6945d --- /dev/null +++ b/src/librustc_platform_intrinsics/x86.rs @@ -0,0 +1,38 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use {Intrinsic, i, f, v}; +use rustc::middle::ty; + +macro_rules! p { + ($name: expr, ($($inputs: tt),*) -> $output: tt) => { + plain!(concat!("llvm.x86.", $name), ($($inputs),*) -> $output) + } +} + +pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { + Some(match name { + "mm_movemask_ps" => p!("sse.movmsk.ps", (f32x4) -> i32), + "mm_movemask_pd" => p!("sse2.movmsk.pd", (f64x2) -> i32), + "mm_movemask_epi8" => p!("sse2.pmovmskb.128", (i8x16) -> i32), + + "mm_rsqrt_ps" => p!("sse.rsqrt.ps", (f32x4) -> f32x4), + + "mm_sqrt_ps" => plain!("llvm.sqrt.v4f32", (f32x4) -> f32x4), + "mm_sqrt_pd" => plain!("llvm.sqrt.v2f64", (f64x2) -> f64x2), + + "mm_max_ps" => p!("sse.max.ps", (f32x4, f32x4) -> f32x4), + "mm_max_pd" => p!("sse2.max.pd", (f64x2, f64x2) -> f64x2), + + "mm_min_ps" => p!("sse.min.ps", (f32x4, f32x4) -> f32x4), + "mm_min_pd" => p!("sse2.min.pd", (f64x2, f64x2) -> f64x2), + _ => return None + }) +} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 6d91ae6fed639..23f21f337f302 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -54,6 +54,7 @@ extern crate libc; extern crate rustc; extern crate rustc_back; extern crate rustc_llvm as llvm; +extern crate rustc_platform_intrinsics as intrinsics; extern crate serialize; #[macro_use] extern crate log; diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 489c54dc6e2d2..f79b62878c1e9 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -11,6 +11,7 @@ #![allow(non_upper_case_globals)] use arena::TypedArena; +use intrinsics::{self, Intrinsic}; use llvm; use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef, TypeKind}; use middle::subst; @@ -905,7 +906,41 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } - (_, _) => ccx.sess().span_bug(foreign_item.span, "unknown intrinsic") + (_, _) => { + match Intrinsic::find(tcx, &name) { + None => ccx.sess().span_bug(foreign_item.span, "unknown intrinsic"), + Some(intr) => { + fn ty_to_type(ccx: &CrateContext, t: &intrinsics::Type) -> Type { + use intrinsics::Type::*; + match *t { + Integer(x) => Type::ix(ccx, x as u64), + Float(x) => { + match x { + 32 => Type::f32(ccx), + 64 => Type::f64(ccx), + _ => unreachable!() + } + } + Pointer(_) => unimplemented!(), + Vector(ref t, length) => Type::vector(&ty_to_type(ccx, t), + length as u64) + } + } + + let inputs = intr.inputs.iter().map(|t| ty_to_type(ccx, t)).collect::>(); + let outputs = ty_to_type(ccx, &intr.output); + match intr.definition { + intrinsics::IntrinsicDef::Named(name) => { + let f = declare::declare_cfn(ccx, + name, + Type::func(&inputs, &outputs), + tcx.mk_nil()); + Call(bcx, f, &llargs, None, call_debug_location) + } + } + } + } + } }; if val_ty(llval) != Type::void(ccx) && diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 749bc8ab2942b..56230ae06f9e1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5378,6 +5378,12 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { (0, vec![tcx.mk_fn(None, fn_ty), mut_u8], mut_u8) } + name if name.starts_with("x86_") || + name.starts_with("arm_") || + name.starts_with("aarch64_") => { + // FIXME: skip checking these for now + return + } ref other => { span_err!(tcx.sess, it.span, E0093, "unrecognized intrinsic function: `{}`", *other); From 78eead63fa91dbe156236b547bb4290f02784712 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 20 Jul 2015 11:55:47 -0700 Subject: [PATCH 07/40] Implement the simd_insert/simd_extract intrinsics. --- src/librustc_trans/trans/intrinsic.rs | 21 ++++++++++++++++++++- src/librustc_typeck/check/mod.rs | 2 ++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index f79b62878c1e9..7c8deb9a791eb 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -1426,5 +1426,24 @@ fn generic_simd_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return ShuffleVector(bcx, llargs[0], llargs[1], C_vector(&indices)) } - C_null(llret_ty) + + if name == "simd_insert" { + require!(arg_tys[0].is_simd(tcx), + "SIMD insert intrinsic monomorphised for non-SIMD input type"); + + let elem_ty = arg_tys[0].simd_type(tcx); + require!(arg_tys[2] == elem_ty, + "SIMD insert intrinsic monomorphised with inserted type not SIMD element type"); + return InsertElement(bcx, llargs[0], llargs[2], llargs[1]) + } + if name == "simd_extract" { + require!(arg_tys[0].is_simd(tcx), + "SIMD insert intrinsic monomorphised for non-SIMD input type"); + + let elem_ty = arg_tys[0].simd_type(tcx); + require!(ret_ty == elem_ty, + "SIMD insert intrinsic monomorphised with returned type not SIMD element type"); + return ExtractElement(bcx, llargs[0], llargs[1]) + } + bcx.sess().span_bug(call_info.span, "unknown SIMD intrinsic"); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 56230ae06f9e1..2821538a29536 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5344,6 +5344,8 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { "simd_eq" | "simd_ne" | "simd_lt" | "simd_le" | "simd_gt" | "simd_ge" => { (2, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 1)) } + "simd_insert" => (2, vec![param(ccx, 0), tcx.types.u32, param(ccx, 1)], param(ccx, 0)), + "simd_extract" => (2, vec![param(ccx, 0), tcx.types.u32], param(ccx, 1)), name if name.starts_with("simd_shuffle") => { match name["simd_shuffle".len()..].parse() { Ok(n) => { From f1d3b0271ef62e52e65962744701861c32534114 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 29 Jul 2015 16:39:21 -0700 Subject: [PATCH 08/40] Add x86 & arm reciprocal approximation intrinsics. --- src/librustc_platform_intrinsics/arm.rs | 1 + src/librustc_platform_intrinsics/x86.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/librustc_platform_intrinsics/arm.rs b/src/librustc_platform_intrinsics/arm.rs index 7fa7d45a600f5..ed1121b98df14 100644 --- a/src/librustc_platform_intrinsics/arm.rs +++ b/src/librustc_platform_intrinsics/arm.rs @@ -35,6 +35,7 @@ pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { "vsqrtq_f32" => plain!("llvm.sqrt.v4f32", (f32x4) -> f32x4), "vsqrtq_f64" => plain!("llvm.sqrt.v2f64", (f64x2) -> f64x2), + "vrecpeq_f32" => p!("vrecpe.v4f32", (f32x4) -> f32x4), "vrsqrteq_f32" => p!("vrsqrte.v4f32", (f32x4) -> f32x4), "vrsqrteq_f64" => p!("vrsqrte.v2f64", (f64x2) -> f64x2), diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs index 93cadf8b6945d..4a8d548a2e4b0 100644 --- a/src/librustc_platform_intrinsics/x86.rs +++ b/src/librustc_platform_intrinsics/x86.rs @@ -24,6 +24,7 @@ pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { "mm_movemask_epi8" => p!("sse2.pmovmskb.128", (i8x16) -> i32), "mm_rsqrt_ps" => p!("sse.rsqrt.ps", (f32x4) -> f32x4), + "mm_rcp_ps" => p!("sse.rcp.ps", (f32x4) -> f32x4), "mm_sqrt_ps" => plain!("llvm.sqrt.v4f32", (f32x4) -> f32x4), "mm_sqrt_pd" => plain!("llvm.sqrt.v2f64", (f64x2) -> f64x2), From ecb3df5a91b71e31e242737d9203b2798bd489de Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 29 Jul 2015 16:40:22 -0700 Subject: [PATCH 09/40] Add simd_cast intrinsic. --- src/librustc_trans/trans/intrinsic.rs | 51 +++++++++++++++++++++++++++ src/librustc_trans/trans/type_of.rs | 8 +++-- src/librustc_typeck/check/mod.rs | 1 + 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 7c8deb9a791eb..88a80076640c3 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -1445,5 +1445,56 @@ fn generic_simd_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, "SIMD insert intrinsic monomorphised with returned type not SIMD element type"); return ExtractElement(bcx, llargs[0], llargs[1]) } + + if name == "simd_cast" { + require!(arg_tys[0].simd_size(tcx) == ret_ty.simd_size(tcx), + "SIMD cast intrinsic monomorphised with input and \ + return types of different lengths"); + // casting cares about nominal type, not just structural type + let in_ = arg_tys[0].simd_type(tcx); + let out = ret_ty.simd_type(tcx); + + if in_ == out { return llargs[0]; } + + match (&in_.sty, &out.sty) { + (&ty::TyInt(lhs), &ty::TyUint(rhs)) => { + match (lhs, rhs) { + (ast::TyI8, ast::TyU8) | + (ast::TyI16, ast::TyU16) | + (ast::TyI32, ast::TyU32) | + (ast::TyI64, ast::TyU64) => return llargs[0], + _ => {}, + } + } + (&ty::TyUint(lhs), &ty::TyInt(rhs)) => { + match (lhs, rhs) { + (ast::TyU8, ast::TyI8) | + (ast::TyU16, ast::TyI16) | + (ast::TyU32, ast::TyI32) | + (ast::TyU64, ast::TyI64) => return llargs[0], + _ => {}, + } + } + (&ty::TyInt(ast::TyI32), &ty::TyFloat(ast::TyF32)) | + (&ty::TyInt(ast::TyI64), &ty::TyFloat(ast::TyF64)) => { + return SIToFP(bcx, llargs[0], llret_ty) + } + (&ty::TyUint(ast::TyU32), &ty::TyFloat(ast::TyF32)) | + (&ty::TyUint(ast::TyU64), &ty::TyFloat(ast::TyF64)) => { + return UIToFP(bcx, llargs[0], llret_ty) + } + + (&ty::TyFloat(ast::TyF32), &ty::TyInt(ast::TyI32)) | + (&ty::TyFloat(ast::TyF64), &ty::TyInt(ast::TyI64)) => { + return FPToSI(bcx, llargs[0], llret_ty) + } + (&ty::TyFloat(ast::TyF32), &ty::TyUint(ast::TyU32)) | + (&ty::TyFloat(ast::TyF64), &ty::TyUint(ast::TyU64)) => { + return FPToUI(bcx, llargs[0], llret_ty) + } + _ => {} + } + require!(false, "SIMD cast intrinsic monomorphised with incompatible cast"); + } bcx.sess().span_bug(call_info.span, "unknown SIMD intrinsic"); } diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 5991d61a1e4ee..3edd4530ceb69 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) @@ -240,6 +241,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 } @@ -426,8 +431,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/mod.rs b/src/librustc_typeck/check/mod.rs index 2821538a29536..742bd57a130e9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5346,6 +5346,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { } "simd_insert" => (2, vec![param(ccx, 0), tcx.types.u32, param(ccx, 1)], param(ccx, 0)), "simd_extract" => (2, vec![param(ccx, 0), tcx.types.u32], param(ccx, 1)), + "simd_cast" => (2, vec![param(ccx, 0)], param(ccx, 1)), name if name.starts_with("simd_shuffle") => { match name["simd_shuffle".len()..].parse() { Ok(n) => { From 8d8b489bc93b2f8754a0de386bd4e960b05a5b47 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Fri, 31 Jul 2015 11:23:12 -0700 Subject: [PATCH 10/40] Add intrinsics for SIMD arithmetic. --- src/librustc_trans/trans/intrinsic.rs | 30 +++++++++++++++++++++++++++ src/librustc_typeck/check/mod.rs | 5 +++++ 2 files changed, 35 insertions(+) diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 88a80076640c3..a31668ad21232 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -1496,5 +1496,35 @@ fn generic_simd_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } require!(false, "SIMD cast intrinsic monomorphised with incompatible cast"); } + macro_rules! arith { + ($($name: ident: $($($p: ident),* => $call: expr),*;)*) => { + $( + if name == stringify!($name) { + let in_ = arg_tys[0].simd_type(tcx); + match in_.sty { + $( + $(ty::$p(_))|* => { + return $call(bcx, llargs[0], llargs[1], call_debug_location) + } + )* + _ => {}, + } + require!(false, + "{} intrinsic monomorphised with invalid type", + name) + })* + } + } + 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_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 742bd57a130e9..2f19d4d9ec23d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5344,6 +5344,11 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { "simd_eq" | "simd_ne" | "simd_lt" | "simd_le" | "simd_gt" | "simd_ge" => { (2, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 1)) } + "simd_add" | "simd_sub" | "simd_mul" | + "simd_div" | "simd_shl" | "simd_shr" | + "simd_and" | "simd_or" | "simd_xor" => { + (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)) + } "simd_insert" => (2, vec![param(ccx, 0), tcx.types.u32, param(ccx, 1)], param(ccx, 0)), "simd_extract" => (2, vec![param(ccx, 0), tcx.types.u32], param(ccx, 1)), "simd_cast" => (2, vec![param(ccx, 0)], param(ccx, 1)), From cb1eb9d0c41739fc6abf4361c263013004463072 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 3 Aug 2015 17:24:12 -0700 Subject: [PATCH 11/40] Remove automatic built-in SIMD operators. These should now go via the intrinsics, and implement the standard traits. --- src/librustc_typeck/check/op.rs | 50 +++------------------------------ 1 file changed, 4 insertions(+), 46 deletions(-) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index b139cb45bf207..59856a4a9c639 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -82,18 +82,6 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, check_expr(fcx, lhs_expr); let lhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr)); - // Annoyingly, SIMD ops don't fit into the PartialEq/PartialOrd - // traits, because their return type is not bool. Perhaps this - // should change, but for now if LHS is SIMD we go down a - // different path that bypassess all traits. - if lhs_ty.is_simd() { - check_expr_coercable_to_type(fcx, rhs_expr, lhs_ty); - let rhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr)); - let return_ty = enforce_builtin_binop_types(fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); - fcx.write_ty(expr.id, return_ty); - return; - } - match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => { // && and || are a simple case. @@ -154,12 +142,6 @@ fn enforce_builtin_binop_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } BinOpCategory::Shift => { - // For integers, the shift amount can be of any integral - // type. For simd, the type must match exactly. - if lhs_ty.is_simd() { - demand::suptype(fcx, rhs_expr.span, lhs_ty, rhs_ty); - } - // result type is same as LHS always lhs_ty } @@ -174,27 +156,7 @@ fn enforce_builtin_binop_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, BinOpCategory::Comparison => { // both LHS and RHS and result will have the same type demand::suptype(fcx, rhs_expr.span, lhs_ty, rhs_ty); - - // if this is simd, result is same as lhs, else bool - if lhs_ty.is_simd() { - let unit_ty = lhs_ty.simd_type(tcx); - debug!("enforce_builtin_binop_types: lhs_ty={:?} unit_ty={:?}", - lhs_ty, - unit_ty); - if !unit_ty.is_integral() { - tcx.sess.span_err( - lhs_expr.span, - &format!("binary comparison operation `{}` not supported \ - for floating point SIMD vector `{}`", - ast_util::binop_to_string(op.node), - lhs_ty)); - tcx.types.err - } else { - lhs_ty - } - } else { - tcx.mk_bool() - } + tcx.mk_bool() } } } @@ -427,29 +389,25 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, BinOpCategory::Shift => { lhs.references_error() || rhs.references_error() || - lhs.is_integral() && rhs.is_integral() || - lhs.is_simd() && rhs.is_simd() + lhs.is_integral() && rhs.is_integral() } BinOpCategory::Math => { lhs.references_error() || rhs.references_error() || lhs.is_integral() && rhs.is_integral() || - lhs.is_floating_point() && rhs.is_floating_point() || - lhs.is_simd() && rhs.is_simd() + lhs.is_floating_point() && rhs.is_floating_point() } BinOpCategory::Bitwise => { lhs.references_error() || rhs.references_error() || lhs.is_integral() && rhs.is_integral() || lhs.is_floating_point() && rhs.is_floating_point() || - lhs.is_simd() && rhs.is_simd() || lhs.is_bool() && rhs.is_bool() } BinOpCategory::Comparison => { lhs.references_error() || rhs.references_error() || - lhs.is_scalar() && rhs.is_scalar() || - lhs.is_simd() && rhs.is_simd() + lhs.is_scalar() && rhs.is_scalar() } } } From 58891278a322f5e09ea0b9da762e37b57fc39d1f Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 5 Aug 2015 09:08:03 -0700 Subject: [PATCH 12/40] Type check platform-intrinsics in typeck. --- mk/crates.mk | 2 +- src/librustc_platform_intrinsics/lib.rs | 2 +- src/librustc_typeck/check/mod.rs | 117 ++++++++++++++++++++++-- src/librustc_typeck/lib.rs | 1 + 4 files changed, 110 insertions(+), 12 deletions(-) diff --git a/mk/crates.mk b/mk/crates.mk index 611f0146285e4..aeb336f844fac 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -75,7 +75,7 @@ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_bo DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \ log syntax serialize rustc_llvm rustc_platform_intrinsics -DEPS_rustc_typeck := rustc syntax +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 diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs index 17e98770e835b..1077a84c5a9f8 100755 --- a/src/librustc_platform_intrinsics/lib.rs +++ b/src/librustc_platform_intrinsics/lib.rs @@ -28,7 +28,7 @@ pub struct Intrinsic { pub definition: IntrinsicDef, } -#[derive(Clone)] +#[derive(Clone, Hash, Eq, PartialEq)] pub enum Type { Integer(u8), Float(u8), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2f19d4d9ec23d..93da9ffb7baa3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -84,6 +84,7 @@ use self::TupleArgumentsFlag::*; use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode}; use check::_match::pat_ctxt; use fmt_macros::{Parser, Piece, Position}; +use intrinsics; use middle::astconv_util::{check_path_args, NO_TPS, NO_REGIONS}; use middle::def; use middle::infer; @@ -109,7 +110,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, HashMap}; use std::iter; use std::mem::replace; use std::slice; @@ -5386,16 +5387,18 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { (0, vec![tcx.mk_fn(None, fn_ty), mut_u8], mut_u8) } - name if name.starts_with("x86_") || - name.starts_with("arm_") || - name.starts_with("aarch64_") => { - // FIXME: skip checking these for now - return - } ref other => { - span_err!(tcx.sess, it.span, E0093, - "unrecognized intrinsic function: `{}`", *other); - return; + match intrinsics::Intrinsic::find(tcx, other) { + Some(intr) => { + check_platform_intrinsic_type(ccx, intr, it); + return + } + None => { + span_err!(tcx.sess, it.span, E0093, + "unrecognized intrinsic function: `{}`", *other); + return; + } + } } }; (n_tps, inputs, ty::FnConverging(output)) @@ -5429,3 +5432,97 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { }); } } + +fn check_platform_intrinsic_type(ccx: &CrateCtxt, + expected: intrinsics::Intrinsic, it: &ast::ForeignItem) { + 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); + if i_n_tps != 0 { + tcx.sess.span_err(it.span, + &format!("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(); + for (i, (expected_arg, arg)) in expected.inputs.iter().zip(&sig.inputs).enumerate() { + match_types(tcx, &format!("argument {}", i + 1), it.span, + &mut structural_to_nomimal, expected_arg, arg); + } + match_types(tcx, "return value", it.span, &mut structural_to_nomimal, + &expected.output, sig.output.unwrap()); + + // 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_types<'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::*; + 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)) => {}, + _ => tcx.sess.span_err(span, + &format!("intrinsic {} has wrong type: found `{}`, \ + expected `i{n}` or `u{n}`", + position, + t, n = bits)), + }, + Float(bits) => match (bits, &t.sty) { + (32, &ty::TyFloat(ast::TyF32)) | + (64, &ty::TyFloat(ast::TyF64)) => {}, + _ => tcx.sess.span_err(span, + &format!("intrinsic {} has wrong type: found `{}`, \ + expected `f{n}`", + position, + t, n = bits)), + }, + Pointer(_) => unimplemented!(), + Vector(ref inner_expected, len) => { + if t.is_simd(tcx) { + let t_len = t.simd_size(tcx); + if len as usize != t_len { + tcx.sess.span_err(span, + &format!("intrinsic {} has wrong type: found \ + vector with length {}, expected length {}", + position, + t_len, len)); + return; + } + let t_ty = t.simd_type(tcx); + { + let previous = structural_to_nominal.entry(expected).or_insert(t); + if *previous != t { + tcx.sess.span_err(span, + &format!("intrinsic {} has wrong type: found `{}`, \ + but already seen this vector type as `{}`", + position, t, previous)); + return; + } + } + match_types(tcx, + position, + span, + structural_to_nominal, + inner_expected, + t_ty) + } else { + tcx.sess.span_err(span, + &format!("intrinsic {} has wrong type: found non-simd type {}, \ + expected simd type", + position, t)); + } + } + } + } +} diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 08fd4d8dee5d5..82a605cd14fa4 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -96,6 +96,7 @@ This API is completely unstable and subject to change. extern crate arena; extern crate fmt_macros; extern crate rustc; +extern crate rustc_platform_intrinsics as intrinsics; pub use rustc::lint; pub use rustc::metadata; From 717da9513f787f6f46726bc62e5d3b173435522e Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 6 Aug 2015 11:11:26 -0700 Subject: [PATCH 13/40] Create "platform-intrinsic" ABI for SIMD/platform intrinsics. This is purposely separate to the "rust-intrinsic" ABI, because these intrinsics are theoretically going to become stable, and should be fine to be independent of the compiler/language internals since they're intimately to the platform. --- src/librustc/metadata/creader.rs | 2 +- src/librustc/metadata/encoder.rs | 2 +- src/librustc_lint/builtin.rs | 5 +- src/librustc_trans/trans/base.rs | 4 +- src/librustc_trans/trans/callee.rs | 7 +- src/librustc_trans/trans/foreign.rs | 10 +- src/librustc_trans/trans/monomorphize.rs | 3 +- src/librustc_typeck/check/mod.rs | 294 +++++++++++++---------- src/libsyntax/abi.rs | 2 + src/libsyntax/feature_gate.rs | 17 +- 10 files changed, 207 insertions(+), 139 deletions(-) diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index c34b2ea58dcc8..3f182b4d2b5bb 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -704,7 +704,7 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> { } fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod) { - if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic { + if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic || fm.abi == abi::PlatformIntrinsic { return; } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 91638f0de7e3f..d9e6e8c12f1e3 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1501,7 +1501,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext, encode_family(rbml_w, FN_FAMILY); encode_bounds_and_type_for_item(rbml_w, ecx, nitem.id); encode_name(rbml_w, nitem.ident.name); - if abi == abi::RustIntrinsic { + if abi == abi::RustIntrinsic || abi == abi::PlatformIntrinsic { encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(nitem)); } encode_attributes(rbml_w, &*nitem.attrs); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f581931647765..523ab7b527a14 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -603,6 +603,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match bare_fn.abi { abi::Rust | abi::RustIntrinsic | + abi::PlatformIntrinsic | abi::RustCall => { return FfiUnsafe( "found function pointer with Rust calling \ @@ -717,7 +718,9 @@ impl LintPass for ImproperCTypes { } match it.node { - ast::ItemForeignMod(ref nmod) if nmod.abi != abi::RustIntrinsic => { + ast::ItemForeignMod(ref nmod) + if nmod.abi != abi::RustIntrinsic && + nmod.abi != abi::PlatformIntrinsic => { for ni in &nmod.items { match ni.node { ast::ForeignItemFn(ref decl, _) => check_foreign_fn(cx, &**decl), diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index c6944e7b75659..6be2bb0846463 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -91,7 +91,7 @@ use std::collections::{HashMap, HashSet}; use std::mem; use std::str; use std::{i8, i16, i32, i64}; -use syntax::abi::{Rust, RustCall, RustIntrinsic, Abi}; +use syntax::abi::{Rust, RustCall, RustIntrinsic, PlatformIntrinsic, Abi}; use syntax::ast_util::local_def; use syntax::attr::AttrMetaMethods; use syntax::attr; @@ -671,7 +671,7 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, Rust | RustCall => { get_extern_rust_fn(ccx, t, &name[..], did) } - RustIntrinsic => { + RustIntrinsic | PlatformIntrinsic => { ccx.sess().bug("unexpected intrinsic in trans_external_path") } _ => { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index d0d5b46ab2839..d201114fd82f9 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -150,7 +150,8 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) } } def::DefFn(did, _) if match expr_ty.sty { - ty::TyBareFn(_, ref f) => f.abi == synabi::RustIntrinsic, + ty::TyBareFn(_, ref f) => f.abi == synabi::RustIntrinsic || + f.abi == synabi::PlatformIntrinsic, _ => false } => { let substs = common::node_id_substs(bcx.ccx(), @@ -671,7 +672,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, (d.llfn, Some(d.llself)) } Intrinsic(node, substs) => { - assert!(abi == synabi::RustIntrinsic); + assert!(abi == synabi::RustIntrinsic || abi == synabi::PlatformIntrinsic); assert!(dest.is_some()); let call_info = match debug_loc { @@ -701,7 +702,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, // Intrinsics should not become actual functions. // We trans them in place in `trans_intrinsic_call` - assert!(abi != synabi::RustIntrinsic); + assert!(abi != synabi::RustIntrinsic && abi != synabi::PlatformIntrinsic); let is_rust_fn = abi == synabi::Rust || abi == synabi::RustCall; diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 225ff52a63c59..b316d105d0cdf 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -34,7 +34,7 @@ use middle::subst::Substs; use std::cmp; use libc::c_uint; use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi}; -use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System}; +use syntax::abi::{PlatformIntrinsic, RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System}; use syntax::codemap::Span; use syntax::parse::token::{InternedString, special_idents}; use syntax::ast; @@ -81,6 +81,10 @@ pub fn llvm_calling_convention(ccx: &CrateContext, // Intrinsics are emitted at the call site ccx.sess().bug("asked to register intrinsic fn"); } + PlatformIntrinsic => { + // Intrinsics are emitted at the call site + ccx.sess().bug("asked to register platform intrinsic fn"); + } Rust => { // FIXME(#3678) Implement linking to foreign fns with Rust ABI @@ -475,7 +479,7 @@ pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) { if let ast::ForeignItemFn(ref decl, _) = foreign_item.node { match foreign_mod.abi { - Rust | RustIntrinsic => {} + Rust | RustIntrinsic | PlatformIntrinsic => {} abi => { let ty = ccx.tcx().node_id_to_type(foreign_item.id); match ty.sty { @@ -612,7 +616,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // normal Rust function. This will be the type of the wrappee fn. match t.sty { ty::TyBareFn(_, ref f) => { - assert!(f.abi != Rust && f.abi != RustIntrinsic); + assert!(f.abi != Rust && f.abi != RustIntrinsic && f.abi != PlatformIntrinsic); } _ => { ccx.sess().bug(&format!("build_rust_fn: extern fn {} has ty {:?}, \ diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index c2d1d19935a03..6527136b60294 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -90,7 +90,8 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }); if let ast_map::NodeForeignItem(_) = map_node { - if ccx.tcx().map.get_foreign_abi(fn_id.node) != abi::RustIntrinsic { + let abi = ccx.tcx().map.get_foreign_abi(fn_id.node); + if abi != abi::RustIntrinsic && abi != abi::PlatformIntrinsic { // Foreign externs don't have to be monomorphized. return (get_item_val(ccx, fn_id.node), mono_ty, true); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 93da9ffb7baa3..47bdd5da1ec56 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -720,6 +720,10 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { for item in &m.items { check_intrinsic_type(ccx, &**item); } + } else if m.abi == abi::PlatformIntrinsic { + for item in &m.items { + check_platform_intrinsic_type(ccx, &**item); + } } else { for item in &m.items { let pty = ccx.tcx.lookup_item_type(local_def(item.id)); @@ -5093,7 +5097,6 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { let tcx = ccx.tcx; let name = it.ident.name.as_str(); - let mut infer_ctxt = None; 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"); @@ -5342,35 +5345,6 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(0))), param(ccx, 0))], tcx.types.u64), - "simd_eq" | "simd_ne" | "simd_lt" | "simd_le" | "simd_gt" | "simd_ge" => { - (2, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 1)) - } - "simd_add" | "simd_sub" | "simd_mul" | - "simd_div" | "simd_shl" | "simd_shr" | - "simd_and" | "simd_or" | "simd_xor" => { - (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)) - } - "simd_insert" => (2, vec![param(ccx, 0), tcx.types.u32, param(ccx, 1)], param(ccx, 0)), - "simd_extract" => (2, vec![param(ccx, 0), tcx.types.u32], param(ccx, 1)), - "simd_cast" => (2, vec![param(ccx, 0)], param(ccx, 1)), - name if name.starts_with("simd_shuffle") => { - match name["simd_shuffle".len()..].parse() { - Ok(n) => { - let mut params = vec![param(ccx, 0), param(ccx, 0)]; - params.extend(iter::repeat(tcx.types.u32).take(n)); - - let ictxt = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); - let ret = ictxt.next_ty_var(); - infer_ctxt = Some(ictxt); - (2, params, ret) - } - Err(_) => { - span_err!(tcx.sess, it.span, E0439, - "invalid `simd_shuffle`, needs length: `{}`", name); - return - } - } - } "try" => { let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8); @@ -5388,17 +5362,9 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { } ref other => { - match intrinsics::Intrinsic::find(tcx, other) { - Some(intr) => { - check_platform_intrinsic_type(ccx, intr, it); - return - } - None => { - span_err!(tcx.sess, it.span, E0093, - "unrecognized intrinsic function: `{}`", *other); - return; - } - } + span_err!(tcx.sess, it.span, E0093, + "unrecognized intrinsic function: `{}`", *other); + return; } }; (n_tps, inputs, ty::FnConverging(output)) @@ -5421,7 +5387,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { i_n_tps, n_tps); } else { require_same_types(tcx, - infer_ctxt.as_ref(), + None, false, it.span, i_ty.ty, @@ -5434,95 +5400,177 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { } fn check_platform_intrinsic_type(ccx: &CrateCtxt, - expected: intrinsics::Intrinsic, it: &ast::ForeignItem) { + 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); - if i_n_tps != 0 { - tcx.sess.span_err(it.span, - &format!("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(); - for (i, (expected_arg, arg)) in expected.inputs.iter().zip(&sig.inputs).enumerate() { - match_types(tcx, &format!("argument {}", i + 1), it.span, - &mut structural_to_nomimal, expected_arg, arg); - } - match_types(tcx, "return value", it.span, &mut structural_to_nomimal, - &expected.output, sig.output.unwrap()); - - // 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_types<'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::*; - 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)) => {}, - _ => tcx.sess.span_err(span, - &format!("intrinsic {} has wrong type: found `{}`, \ - expected `i{n}` or `u{n}`", - position, - t, n = bits)), - }, - Float(bits) => match (bits, &t.sty) { - (32, &ty::TyFloat(ast::TyF32)) | - (64, &ty::TyFloat(ast::TyF64)) => {}, - _ => tcx.sess.span_err(span, - &format!("intrinsic {} has wrong type: found `{}`, \ - expected `f{n}`", - position, - t, n = bits)), - }, - Pointer(_) => unimplemented!(), - Vector(ref inner_expected, len) => { - if t.is_simd(tcx) { - let t_len = t.simd_size(tcx); - if len as usize != t_len { - tcx.sess.span_err(span, - &format!("intrinsic {} has wrong type: found \ - vector with length {}, expected length {}", - position, - t_len, len)); - return; + let name = it.ident.name.as_str(); + let mut infer_ctxt = None; + + 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 mut params = vec![param(0), param(0)]; + params.extend(iter::repeat(tcx.types.u32).take(n)); + + let ictxt = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); + let ret = ictxt.next_ty_var(); + infer_ctxt = Some(ictxt); + (2, params, ret) + } + 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 { + tcx.sess.span_err(it.span, + &format!("intrinsic has wrong number of type parameters: \ + found {}, expected 0", + i_n_tps)); + return } - let t_ty = t.simd_type(tcx); - { - let previous = structural_to_nominal.entry(expected).or_insert(t); - if *previous != t { - tcx.sess.span_err(span, - &format!("intrinsic {} has wrong type: found `{}`, \ - but already seen this vector type as `{}`", - position, t, previous)); - 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_types(tcx, - position, - span, - structural_to_nominal, - inner_expected, - t_ty) - } else { + match_intrinsic_type_to_type(tcx, "return value", it.span, + &mut structural_to_nomimal, + &intr.output, sig.output.unwrap()); + return + } + None => { + tcx.sess.span_err(it.span, + &format!("unrecognized intrinsic function: `{}`", name)); + return; + } + } + } + }; + + let fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { + unsafety: ast::Unsafety::Unsafe, + abi: abi::PlatformIntrinsic, + sig: ty::Binder(FnSig { + inputs: inputs, + output: ty::FnConverging(output), + variadic: false, + }), + })); + 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, + infer_ctxt.as_ref(), + false, + it.span, + i_ty.ty, + fty, + || { + format!("intrinsic has wrong type: expected `{}`", + fty) + }); + } +} + +// 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::*; + 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)) => {}, + _ => tcx.sess.span_err(span, + &format!("intrinsic {} has wrong type: found `{}`, \ + expected `i{n}` or `u{n}`", + position, + t, n = bits)), + }, + Float(bits) => match (bits, &t.sty) { + (32, &ty::TyFloat(ast::TyF32)) | + (64, &ty::TyFloat(ast::TyF64)) => {}, + _ => tcx.sess.span_err(span, + &format!("intrinsic {} has wrong type: found `{}`, \ + expected `f{n}`", + position, + t, n = bits)), + }, + Pointer(_) => unimplemented!(), + Vector(ref inner_expected, len) => { + if !t.is_simd(tcx) { + tcx.sess.span_err(span, + &format!("intrinsic {} has wrong type: found non-simd type {}, \ + expected simd type", + position, t)); + return; + } + let t_len = t.simd_size(tcx); + if len as usize != t_len { + tcx.sess.span_err(span, + &format!("intrinsic {} has wrong type: found \ + vector with length {}, expected length {}", + position, + t_len, len)); + return; + } + let t_ty = t.simd_type(tcx); + { + let previous = structural_to_nominal.entry(expected).or_insert(t); + if *previous != t { tcx.sess.span_err(span, - &format!("intrinsic {} has wrong type: found non-simd type {}, \ - expected simd type", - position, t)); + &format!("intrinsic {} has wrong type: found `{}`, \ + but already seen this vector type as `{}`", + position, t, previous)); + return; } } + match_intrinsic_type_to_type(tcx, + position, + span, + structural_to_nominal, + inner_expected, + t_ty) } } } diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 50c86a80b4ab5..c0fe541ead510 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -47,6 +47,7 @@ pub enum Abi { System, RustIntrinsic, RustCall, + PlatformIntrinsic, } #[allow(non_camel_case_types)] @@ -95,6 +96,7 @@ const AbiDatas: &'static [AbiData] = &[ AbiData {abi: System, name: "system" }, AbiData {abi: RustIntrinsic, name: "rust-intrinsic" }, AbiData {abi: RustCall, name: "rust-call" }, + AbiData {abi: PlatformIntrinsic, name: "platform-intrinsic" } ]; /// Returns the ABI with the given name (if any). diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9a1c97a4d29f5..b0167d75bc007 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -184,6 +184,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ // Allows cfg(target_feature = "..."). ("cfg_target_feature", "1.3.0", Active), + + // allow `extern "platform-intrinsic" { ... }` + ("platform_intrinsics", "1.4.0", Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -694,10 +697,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) } } From dbcd9f00d1d66e9f245c3b934fe9530982430824 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 6 Aug 2015 11:29:26 -0700 Subject: [PATCH 14/40] Create separate module for intrinsic typechecking. --- src/librustc_typeck/check/intrinsic.rs | 520 +++++++++++++++++++++++++ src/librustc_typeck/check/mod.rs | 499 +----------------------- 2 files changed, 525 insertions(+), 494 deletions(-) create mode 100644 src/librustc_typeck/check/intrinsic.rs diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs new file mode 100644 index 0000000000000..86c106a234df2 --- /dev/null +++ b/src/librustc_typeck/check/intrinsic.rs @@ -0,0 +1,520 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Type-checking for the rust-intrinsic and platform-intrinsic +//! intrinsics that the compiler exposes. + +use astconv::AstConv; +use intrinsics; +use middle::infer; +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 std::iter; +use syntax::abi; +use syntax::attr::AttrMetaMethods; +use syntax::ast; +use syntax::ast_util::local_def; +use syntax::codemap::Span; +use syntax::parse::token; + + +/// 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) + }); + } +} + +/// 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 mut infer_ctxt = None; + + 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 mut params = vec![param(0), param(0)]; + params.extend(iter::repeat(tcx.types.u32).take(n)); + + let ictxt = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); + let ret = ictxt.next_ty_var(); + infer_ctxt = Some(ictxt); + (2, params, ret) + } + 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 { + tcx.sess.span_err(it.span, + &format!("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 => { + tcx.sess.span_err(it.span, + &format!("unrecognized intrinsic function: `{}`", name)); + return; + } + } + } + }; + + let fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { + unsafety: ast::Unsafety::Unsafe, + abi: abi::PlatformIntrinsic, + sig: ty::Binder(FnSig { + inputs: inputs, + output: ty::FnConverging(output), + variadic: false, + }), + })); + 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, + infer_ctxt.as_ref(), + false, + it.span, + i_ty.ty, + fty, + || { + format!("intrinsic has wrong type: expected `{}`", + fty) + }); + } +} + +// 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::*; + 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)) => {}, + _ => tcx.sess.span_err(span, + &format!("intrinsic {} has wrong type: found `{}`, \ + expected `i{n}` or `u{n}`", + position, + t, n = bits)), + }, + Float(bits) => match (bits, &t.sty) { + (32, &ty::TyFloat(ast::TyF32)) | + (64, &ty::TyFloat(ast::TyF64)) => {}, + _ => tcx.sess.span_err(span, + &format!("intrinsic {} has wrong type: found `{}`, \ + expected `f{n}`", + position, + t, n = bits)), + }, + Pointer(_) => unimplemented!(), + Vector(ref inner_expected, len) => { + if !t.is_simd(tcx) { + tcx.sess.span_err(span, + &format!("intrinsic {} has wrong type: found non-simd type {}, \ + expected simd type", + position, t)); + return; + } + let t_len = t.simd_size(tcx); + if len as usize != t_len { + tcx.sess.span_err(span, + &format!("intrinsic {} has wrong type: found \ + vector with length {}, expected length {}", + position, + t_len, len)); + return; + } + let t_ty = t.simd_type(tcx); + { + let previous = structural_to_nominal.entry(expected).or_insert(t); + if *previous != t { + tcx.sess.span_err(span, + &format!("intrinsic {} has wrong type: found `{}`, \ + but already seen this vector type as `{}`", + 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 47bdd5da1ec56..500e4287d61b8 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -84,7 +84,6 @@ use self::TupleArgumentsFlag::*; use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode}; use check::_match::pat_ctxt; use fmt_macros::{Parser, Piece, Position}; -use intrinsics; use middle::astconv_util::{check_path_args, NO_TPS, NO_REGIONS}; use middle::def; use middle::infer; @@ -102,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}; @@ -110,8 +109,7 @@ use util::nodemap::{DefIdMap, FnvHashMap, NodeMap}; use util::lev_distance::lev_distance; use std::cell::{Cell, Ref, RefCell}; -use std::collections::{HashSet, HashMap}; -use std::iter; +use std::collections::{HashSet}; use std::mem::replace; use std::slice; use syntax::{self, abi, attr}; @@ -141,6 +139,7 @@ mod cast; mod closure; mod callee; mod compare_method; +mod intrinsic; mod op; /// closures defined within the function. For example: @@ -718,11 +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 { - check_platform_intrinsic_type(ccx, &**item); + intrinsic::check_platform_intrinsic_type(ccx, &**item); } } else { for item in &m.items { @@ -5086,491 +5085,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) - }); - } -} - -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 mut infer_ctxt = None; - - 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 mut params = vec![param(0), param(0)]; - params.extend(iter::repeat(tcx.types.u32).take(n)); - - let ictxt = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); - let ret = ictxt.next_ty_var(); - infer_ctxt = Some(ictxt); - (2, params, ret) - } - 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 { - tcx.sess.span_err(it.span, - &format!("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 => { - tcx.sess.span_err(it.span, - &format!("unrecognized intrinsic function: `{}`", name)); - return; - } - } - } - }; - - let fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { - unsafety: ast::Unsafety::Unsafe, - abi: abi::PlatformIntrinsic, - sig: ty::Binder(FnSig { - inputs: inputs, - output: ty::FnConverging(output), - variadic: false, - }), - })); - 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, - infer_ctxt.as_ref(), - false, - it.span, - i_ty.ty, - fty, - || { - format!("intrinsic has wrong type: expected `{}`", - fty) - }); - } -} - -// 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::*; - 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)) => {}, - _ => tcx.sess.span_err(span, - &format!("intrinsic {} has wrong type: found `{}`, \ - expected `i{n}` or `u{n}`", - position, - t, n = bits)), - }, - Float(bits) => match (bits, &t.sty) { - (32, &ty::TyFloat(ast::TyF32)) | - (64, &ty::TyFloat(ast::TyF64)) => {}, - _ => tcx.sess.span_err(span, - &format!("intrinsic {} has wrong type: found `{}`, \ - expected `f{n}`", - position, - t, n = bits)), - }, - Pointer(_) => unimplemented!(), - Vector(ref inner_expected, len) => { - if !t.is_simd(tcx) { - tcx.sess.span_err(span, - &format!("intrinsic {} has wrong type: found non-simd type {}, \ - expected simd type", - position, t)); - return; - } - let t_len = t.simd_size(tcx); - if len as usize != t_len { - tcx.sess.span_err(span, - &format!("intrinsic {} has wrong type: found \ - vector with length {}, expected length {}", - position, - t_len, len)); - return; - } - let t_ty = t.simd_type(tcx); - { - let previous = structural_to_nominal.entry(expected).or_insert(t); - if *previous != t { - tcx.sess.span_err(span, - &format!("intrinsic {} has wrong type: found `{}`, \ - but already seen this vector type as `{}`", - position, t, previous)); - return; - } - } - match_intrinsic_type_to_type(tcx, - position, - span, - structural_to_nominal, - inner_expected, - t_ty) - } - } -} From 48f3507763c646e2353e84f6b0e7269784588d17 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 6 Aug 2015 14:52:40 -0700 Subject: [PATCH 15/40] Use error codes for platform-intrinsic typeck errors. --- src/librustc_typeck/check/intrinsic.rs | 165 ++++++++++++------------- src/librustc_typeck/diagnostics.rs | 7 +- 2 files changed, 88 insertions(+), 84 deletions(-) diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 86c106a234df2..0df497877ae17 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -29,6 +29,41 @@ 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, + maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>, + n_tps: usize, + abi: abi::Abi, + inputs: Vec>, + output: ty::FnOutput<'tcx>) { + let fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { + unsafety: ast::Unsafety::Unsafe, + abi: abi, + sig: ty::Binder(FnSig { + inputs: inputs, + output: output, + variadic: false, + }), + })); + let i_ty = tcx.lookup_item_type(local_def(it.id)); + let i_n_tps = i_ty.generics.types.len(subst::FnSpace); + if i_n_tps != n_tps { + span_err!(tcx.sess, it.span, E0094, + "intrinsic has wrong number of type \ + parameters: found {}, expected {}", + i_n_tps, n_tps); + } else { + require_same_types(tcx, + maybe_infcx, + 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 @@ -312,34 +347,15 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { }; (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) - }); - } + equate_intrinsic_type( + tcx, + it, + None, + n_tps, + abi::RustIntrinsic, + inputs, + output + ) } /// Type-check `extern "platform-intrinsic" { ... }` functions. @@ -391,10 +407,10 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, Some(intr) => { // this function is a platform specific intrinsic if i_n_tps != 0 { - tcx.sess.span_err(it.span, - &format!("intrinsic has wrong number of type parameters: \ - found {}, expected 0", - i_n_tps)); + span_err!(tcx.sess, it.span, E0440, + "platform-specific intrinsic has wrong number of type \ + parameters: found {}, expected 0", + i_n_tps); return } @@ -412,40 +428,23 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, return } None => { - tcx.sess.span_err(it.span, - &format!("unrecognized intrinsic function: `{}`", name)); + span_err!(tcx.sess, it.span, E0441, + "unrecognized platform-specific intrinsic function: `{}`", name); return; } } } }; - let fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { - unsafety: ast::Unsafety::Unsafe, - abi: abi::PlatformIntrinsic, - sig: ty::Binder(FnSig { - inputs: inputs, - output: ty::FnConverging(output), - variadic: false, - }), - })); - 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, - infer_ctxt.as_ref(), - false, - it.span, - i_ty.ty, - fty, - || { - format!("intrinsic has wrong type: expected `{}`", - fty) - }); - } + equate_intrinsic_type( + tcx, + it, + infer_ctxt.as_ref(), + n_tps, + abi::PlatformIntrinsic, + inputs, + ty::FnConverging(output) + ) } // walk the expected type and the actual type in lock step, checking they're @@ -459,53 +458,53 @@ fn match_intrinsic_type_to_type<'tcx, 'a>( 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)) => {}, - _ => tcx.sess.span_err(span, - &format!("intrinsic {} has wrong type: found `{}`, \ - expected `i{n}` or `u{n}`", - position, - t, n = bits)), + _ => 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)) => {}, - _ => tcx.sess.span_err(span, - &format!("intrinsic {} has wrong type: found `{}`, \ - expected `f{n}`", - position, - t, n = bits)), + _ => simple_error(&format!("`{}`", t), + &format!("`f{n}`", n = bits)), }, Pointer(_) => unimplemented!(), Vector(ref inner_expected, len) => { if !t.is_simd(tcx) { - tcx.sess.span_err(span, - &format!("intrinsic {} has wrong type: found non-simd type {}, \ - expected simd type", - position, t)); + simple_error(&format!("non-simd type `{}`", t), + "simd type"); return; } let t_len = t.simd_size(tcx); if len as usize != t_len { - tcx.sess.span_err(span, - &format!("intrinsic {} has wrong type: found \ - vector with length {}, expected length {}", - position, - t_len, 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 { - tcx.sess.span_err(span, - &format!("intrinsic {} has wrong type: found `{}`, \ - but already seen this vector type as `{}`", - position, t, previous)); + // 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; } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 093ffc6a9963e..e8660e57a3ca3 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -2801,5 +2801,10 @@ register_diagnostics! { E0399, // trait items need to be implemented because the associated // type `{}` was overridden E0436, // functional record update requires a struct - E0439 // invalid `simd_shuffle`, needs length: `{}` + 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 } From bef1828d427a3eb9f57d865efc4b615b08714b46 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 6 Aug 2015 16:03:41 -0700 Subject: [PATCH 16/40] Rename `simd_basics` feature gate to `repr_simd`. --- src/libcore/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index c064d87e37026..d21cfbcdfce9b 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -79,7 +79,7 @@ #![feature(reflect)] #![feature(rustc_attrs)] #![cfg_attr(stage0, feature(simd))] -#![cfg_attr(not(stage0), feature(simd_basics))] +#![cfg_attr(not(stage0), feature(repr_simd))] #![feature(staged_api)] #![feature(unboxed_closures)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index b0167d75bc007..f5a0a2f4718b9 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -180,10 +180,10 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ ("type_macros", "1.3.0", Active), // allow `repr(simd)`, and importing the various simd intrinsics - ("simd_basics", "1.3.0", Active), + ("repr_simd", "1.4.0", Active), // Allows cfg(target_feature = "..."). - ("cfg_target_feature", "1.3.0", Active), + ("cfg_target_feature", "1.4.0", Active), // allow `extern "platform-intrinsic" { ... }` ("platform_intrinsics", "1.4.0", Active), @@ -422,7 +422,6 @@ pub struct Features { pub allow_box: bool, pub allow_pushpop_unsafe: bool, pub simd_ffi: bool, - pub simd_basics: bool, pub unmarked_api: bool, pub negate_unsigned: bool, /// spans of #![feature] attrs for stable language features. for error reporting @@ -453,7 +452,6 @@ impl Features { allow_box: false, allow_pushpop_unsafe: false, simd_ffi: false, - simd_basics: false, unmarked_api: false, negate_unsigned: false, declared_stable_lang_features: Vec::new(), @@ -741,7 +739,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { if attr.name() == "repr" { for item in attr.meta_item_list().unwrap_or(&[]) { if item.name() == "simd" { - self.gate_feature("simd_basics", i.span, + self.gate_feature("repr_simd", i.span, "SIMD types are experimental and possibly buggy"); } @@ -979,7 +977,6 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, allow_box: cx.has_feature("box_syntax"), allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"), simd_ffi: cx.has_feature("simd_ffi"), - simd_basics: cx.has_feature("simd_basics"), unmarked_api: cx.has_feature("unmarked_api"), negate_unsigned: cx.has_feature("negate_unsigned"), declared_stable_lang_features: accepted_features, From 4fe138cac07bff2cc4185a9a5a71c677f88f0562 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 10 Aug 2015 16:32:30 -0700 Subject: [PATCH 17/40] Add _mm_shuffle_epi8 intrinsic. --- src/librustc_platform_intrinsics/x86.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs index 4a8d548a2e4b0..631e1c423182a 100644 --- a/src/librustc_platform_intrinsics/x86.rs +++ b/src/librustc_platform_intrinsics/x86.rs @@ -34,6 +34,8 @@ pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { "mm_min_ps" => p!("sse.min.ps", (f32x4, f32x4) -> f32x4), "mm_min_pd" => p!("sse2.min.pd", (f64x2, f64x2) -> f64x2), + + "mm_shuffle_epi8" => p!("ssse3.pshuf.b.128", (i8x16, i8x16) -> i8x16), _ => return None }) } From 9b26895346029c817079033fe95727060b73f655 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 10 Aug 2015 16:34:25 -0700 Subject: [PATCH 18/40] Generalise SIMD casting to unequal bitwidths. --- src/librustc_trans/trans/intrinsic.rs | 97 ++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 10 deletions(-) diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index a31668ad21232..735d5d224845e 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -1457,13 +1457,73 @@ fn generic_simd_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, if in_ == out { return llargs[0]; } match (&in_.sty, &out.sty) { + (&ty::TyInt(lhs), &ty::TyInt(rhs)) => { + match (lhs, rhs) { + (ast::TyI8, ast::TyI8) | + (ast::TyI16, ast::TyI16) | + (ast::TyI32, ast::TyI32) | + (ast::TyI64, ast::TyI64) => return llargs[0], + + (ast::TyI8, ast::TyI16) | + (ast::TyI8, ast::TyI32) | + (ast::TyI8, ast::TyI64) | + (ast::TyI16, ast::TyI32) | + (ast::TyI16, ast::TyI64) | + (ast::TyI32, ast::TyI64) => return SExt(bcx, llargs[0], llret_ty), + + (ast::TyI16, ast::TyI8) | + (ast::TyI32, ast::TyI8) | + (ast::TyI32, ast::TyI16) | + (ast::TyI64, ast::TyI8) | + (ast::TyI64, ast::TyI16) | + (ast::TyI64, ast::TyI32) => return Trunc(bcx, llargs[0], llret_ty), + _ => {} + } + } + (&ty::TyUint(lhs), &ty::TyUint(rhs)) => { + match (lhs, rhs) { + (ast::TyU8, ast::TyU8) | + (ast::TyU16, ast::TyU16) | + (ast::TyU32, ast::TyU32) | + (ast::TyU64, ast::TyU64) => return llargs[0], + + (ast::TyU8, ast::TyU16) | + (ast::TyU8, ast::TyU32) | + (ast::TyU8, ast::TyU64) | + (ast::TyU16, ast::TyU32) | + (ast::TyU16, ast::TyU64) | + (ast::TyU32, ast::TyU64) => return ZExt(bcx, llargs[0], llret_ty), + + (ast::TyU16, ast::TyU8) | + (ast::TyU32, ast::TyU8) | + (ast::TyU32, ast::TyU16) | + (ast::TyU64, ast::TyU8) | + (ast::TyU64, ast::TyU16) | + (ast::TyU64, ast::TyU32) => return Trunc(bcx, llargs[0], llret_ty), + _ => {} + } + } (&ty::TyInt(lhs), &ty::TyUint(rhs)) => { match (lhs, rhs) { (ast::TyI8, ast::TyU8) | (ast::TyI16, ast::TyU16) | (ast::TyI32, ast::TyU32) | (ast::TyI64, ast::TyU64) => return llargs[0], - _ => {}, + + (ast::TyI8, ast::TyU16) | + (ast::TyI8, ast::TyU32) | + (ast::TyI8, ast::TyU64) | + (ast::TyI16, ast::TyU32) | + (ast::TyI16, ast::TyU64) | + (ast::TyI32, ast::TyU64) => return SExt(bcx, llargs[0], llret_ty), + + (ast::TyI16, ast::TyU8) | + (ast::TyI32, ast::TyU8) | + (ast::TyI32, ast::TyU16) | + (ast::TyI64, ast::TyU8) | + (ast::TyI64, ast::TyU16) | + (ast::TyI64, ast::TyU32) => return Trunc(bcx, llargs[0], llret_ty), + _ => {} } } (&ty::TyUint(lhs), &ty::TyInt(rhs)) => { @@ -1472,26 +1532,43 @@ fn generic_simd_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, (ast::TyU16, ast::TyI16) | (ast::TyU32, ast::TyI32) | (ast::TyU64, ast::TyI64) => return llargs[0], - _ => {}, + + (ast::TyU8, ast::TyI16) | + (ast::TyU8, ast::TyI32) | + (ast::TyU8, ast::TyI64) | + (ast::TyU16, ast::TyI32) | + (ast::TyU16, ast::TyI64) | + (ast::TyU32, ast::TyI64) => return ZExt(bcx, llargs[0], llret_ty), + + (ast::TyU16, ast::TyI8) | + (ast::TyU32, ast::TyI8) | + (ast::TyU32, ast::TyI16) | + (ast::TyU64, ast::TyI8) | + (ast::TyU64, ast::TyI16) | + (ast::TyU64, ast::TyI32) => return Trunc(bcx, llargs[0], llret_ty), + _ => {} } } - (&ty::TyInt(ast::TyI32), &ty::TyFloat(ast::TyF32)) | - (&ty::TyInt(ast::TyI64), &ty::TyFloat(ast::TyF64)) => { + + (&ty::TyInt(_), &ty::TyFloat(_)) => { return SIToFP(bcx, llargs[0], llret_ty) } - (&ty::TyUint(ast::TyU32), &ty::TyFloat(ast::TyF32)) | - (&ty::TyUint(ast::TyU64), &ty::TyFloat(ast::TyF64)) => { + (&ty::TyUint(_), &ty::TyFloat(_)) => { return UIToFP(bcx, llargs[0], llret_ty) } - (&ty::TyFloat(ast::TyF32), &ty::TyInt(ast::TyI32)) | - (&ty::TyFloat(ast::TyF64), &ty::TyInt(ast::TyI64)) => { + (&ty::TyFloat(_), &ty::TyInt(_)) => { return FPToSI(bcx, llargs[0], llret_ty) } - (&ty::TyFloat(ast::TyF32), &ty::TyUint(ast::TyU32)) | - (&ty::TyFloat(ast::TyF64), &ty::TyUint(ast::TyU64)) => { + (&ty::TyFloat(_), &ty::TyUint(_)) => { return FPToUI(bcx, llargs[0], llret_ty) } + (&ty::TyFloat(ast::TyF32), &ty::TyFloat(ast::TyF64)) => { + return FPExt(bcx, llargs[0], llret_ty) + } + (&ty::TyFloat(ast::TyF64), &ty::TyFloat(ast::TyF32)) => { + return FPTrunc(bcx, llargs[0], llret_ty) + } _ => {} } require!(false, "SIMD cast intrinsic monomorphised with incompatible cast"); From e61f5397dbb1c0b7e007eb3a09161c590deda336 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 10 Aug 2015 17:15:34 -0700 Subject: [PATCH 19/40] Add most SSE2 intrinsics. --- src/librustc_platform_intrinsics/x86.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs index 631e1c423182a..6fda7f18e3e9c 100644 --- a/src/librustc_platform_intrinsics/x86.rs +++ b/src/librustc_platform_intrinsics/x86.rs @@ -36,6 +36,30 @@ pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { "mm_min_pd" => p!("sse2.min.pd", (f64x2, f64x2) -> f64x2), "mm_shuffle_epi8" => p!("ssse3.pshuf.b.128", (i8x16, i8x16) -> i8x16), + + "mm_adds_epi16" => p!("sse2.padds.w", (i16x8, i16x8) -> i16x8), + "mm_adds_epi8" => p!("sse2.padds.b", (i8x16, i8x16) -> i8x16), + "mm_adds_epu16" => p!("sse2.paddus.w", (i16x8, i16x8) -> i16x8), + "mm_adds_epu8" => p!("sse2.paddus.b", (i8x16, i8x16) -> i8x16), + "mm_avg_epu16" => p!("sse2.pavg.w", (i16x8, i16x8) -> i16x8), + "mm_avg_epu8" => p!("sse2.pavg.b", (i8x16, i8x16) -> i8x16), + "mm_madd_epi16" => p!("sse2.pmadd.wd", (i16x8, i16x8) -> i32x4), + "mm_max_epi16" => p!("sse2.pmaxs.w", (i16x8, i16x8) -> i16x8), + "mm_max_epu8" => p!("sse2.pmaxu.b", (i8x16, i8x16) -> i8x16), + "mm_min_epi16" => p!("sse2.pmins.w", (i16x8, i16x8) -> i16x8), + "mm_min_epu8" => p!("sse2.pminu.b", (i8x16, i8x16) -> i8x16), + "mm_mul_epu32" => p!("sse2.pmulu.dq", (i32x4, i32x4) -> i64x2), + "mm_mulhi_epi16" => p!("sse2.pmulh.w", (i8x16, i8x16) -> i8x16), + "mm_mulhi_epu16" => p!("sse2.pmulhu.w", (i8x16, i8x16) -> i8x16), + "mm_packs_epi16" => p!("sse2.packsswb.128", (i16x8, i16x8) -> i8x16), + "mm_packs_epi32" => p!("sse2.packssdw.128", (i32x4, i32x4) -> i16x8), + "mm_packus_epi16" => p!("sse2.packuswb.128", (i16x8, i16x8) -> i8x16), + "mm_sad_epu8" => p!("sse2.psad.bw", (i8x16, i8x16) -> i64x2), + "mm_subs_epi16" => p!("sse2.psubs.w", (i16x8, i16x8) -> i16x8), + "mm_subs_epi8" => p!("sse2.psubs.b", (i8x16, i8x16) -> i8x16), + "mm_subs_epu16" => p!("sse2.psubus.w", (i16x8, i16x8) -> i16x8), + "mm_subs_epu8" => p!("sse2.psubus.b", (i8x16, i8x16) -> i8x16), + _ => return None }) } From 907bbac40fe22113bdf19023f1831faada7b7ec0 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 10 Aug 2015 17:20:32 -0700 Subject: [PATCH 20/40] Reorganise x86 intrinsic definitions. - factor out redundant mm prefix - group methods by instruction set --- src/librustc_platform_intrinsics/x86.rs | 82 ++++++++++++------------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs index 6fda7f18e3e9c..bc4428d2cb50d 100644 --- a/src/librustc_platform_intrinsics/x86.rs +++ b/src/librustc_platform_intrinsics/x86.rs @@ -18,48 +18,46 @@ macro_rules! p { } pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { - Some(match name { - "mm_movemask_ps" => p!("sse.movmsk.ps", (f32x4) -> i32), - "mm_movemask_pd" => p!("sse2.movmsk.pd", (f64x2) -> i32), - "mm_movemask_epi8" => p!("sse2.pmovmskb.128", (i8x16) -> i32), - - "mm_rsqrt_ps" => p!("sse.rsqrt.ps", (f32x4) -> f32x4), - "mm_rcp_ps" => p!("sse.rcp.ps", (f32x4) -> f32x4), - - "mm_sqrt_ps" => plain!("llvm.sqrt.v4f32", (f32x4) -> f32x4), - "mm_sqrt_pd" => plain!("llvm.sqrt.v2f64", (f64x2) -> f64x2), - - "mm_max_ps" => p!("sse.max.ps", (f32x4, f32x4) -> f32x4), - "mm_max_pd" => p!("sse2.max.pd", (f64x2, f64x2) -> f64x2), - - "mm_min_ps" => p!("sse.min.ps", (f32x4, f32x4) -> f32x4), - "mm_min_pd" => p!("sse2.min.pd", (f64x2, f64x2) -> f64x2), - - "mm_shuffle_epi8" => p!("ssse3.pshuf.b.128", (i8x16, i8x16) -> i8x16), - - "mm_adds_epi16" => p!("sse2.padds.w", (i16x8, i16x8) -> i16x8), - "mm_adds_epi8" => p!("sse2.padds.b", (i8x16, i8x16) -> i8x16), - "mm_adds_epu16" => p!("sse2.paddus.w", (i16x8, i16x8) -> i16x8), - "mm_adds_epu8" => p!("sse2.paddus.b", (i8x16, i8x16) -> i8x16), - "mm_avg_epu16" => p!("sse2.pavg.w", (i16x8, i16x8) -> i16x8), - "mm_avg_epu8" => p!("sse2.pavg.b", (i8x16, i8x16) -> i8x16), - "mm_madd_epi16" => p!("sse2.pmadd.wd", (i16x8, i16x8) -> i32x4), - "mm_max_epi16" => p!("sse2.pmaxs.w", (i16x8, i16x8) -> i16x8), - "mm_max_epu8" => p!("sse2.pmaxu.b", (i8x16, i8x16) -> i8x16), - "mm_min_epi16" => p!("sse2.pmins.w", (i16x8, i16x8) -> i16x8), - "mm_min_epu8" => p!("sse2.pminu.b", (i8x16, i8x16) -> i8x16), - "mm_mul_epu32" => p!("sse2.pmulu.dq", (i32x4, i32x4) -> i64x2), - "mm_mulhi_epi16" => p!("sse2.pmulh.w", (i8x16, i8x16) -> i8x16), - "mm_mulhi_epu16" => p!("sse2.pmulhu.w", (i8x16, i8x16) -> i8x16), - "mm_packs_epi16" => p!("sse2.packsswb.128", (i16x8, i16x8) -> i8x16), - "mm_packs_epi32" => p!("sse2.packssdw.128", (i32x4, i32x4) -> i16x8), - "mm_packus_epi16" => p!("sse2.packuswb.128", (i16x8, i16x8) -> i8x16), - "mm_sad_epu8" => p!("sse2.psad.bw", (i8x16, i8x16) -> i64x2), - "mm_subs_epi16" => p!("sse2.psubs.w", (i16x8, i16x8) -> i16x8), - "mm_subs_epi8" => p!("sse2.psubs.b", (i8x16, i8x16) -> i8x16), - "mm_subs_epu16" => p!("sse2.psubus.w", (i16x8, i16x8) -> i16x8), - "mm_subs_epu8" => p!("sse2.psubus.b", (i8x16, i8x16) -> i8x16), - + if !name.starts_with("mm_") { return None } + + 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), + + "shuffle_epi8" => p!("ssse3.pshuf.b.128", (i8x16, i8x16) -> i8x16), _ => return None }) } From 9d78efbd601935ec11ce1b5f3dbadb9e3123fe2b Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 10 Aug 2015 17:24:15 -0700 Subject: [PATCH 21/40] Add most SSE3 intrinsics. --- src/librustc_platform_intrinsics/x86.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs index bc4428d2cb50d..bfbdc76beee02 100644 --- a/src/librustc_platform_intrinsics/x86.rs +++ b/src/librustc_platform_intrinsics/x86.rs @@ -57,6 +57,13 @@ pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { "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), + "shuffle_epi8" => p!("ssse3.pshuf.b.128", (i8x16, i8x16) -> i8x16), _ => return None }) From f6275b760c8638985cef7c6ee0a694a1b0eff661 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 10 Aug 2015 17:33:06 -0700 Subject: [PATCH 22/40] Add most SSSE3 intrinsics. --- src/librustc_platform_intrinsics/x86.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs index bfbdc76beee02..2085342d11d80 100644 --- a/src/librustc_platform_intrinsics/x86.rs +++ b/src/librustc_platform_intrinsics/x86.rs @@ -64,7 +64,21 @@ pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { "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), _ => return None }) } From 627784b186e49648f63af0dc24cd912a7b53d56d Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 10 Aug 2015 17:46:02 -0700 Subject: [PATCH 23/40] Add most SSE4.1 intrinsics. --- src/librustc_platform_intrinsics/x86.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs index 2085342d11d80..32a8674460dac 100644 --- a/src/librustc_platform_intrinsics/x86.rs +++ b/src/librustc_platform_intrinsics/x86.rs @@ -79,6 +79,21 @@ pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { "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), _ => return None }) } From 67d56db16fe1e8190d704572de41941e568ed568 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 10 Aug 2015 17:50:31 -0700 Subject: [PATCH 24/40] Rearrange x86 intrinsics to prepare for AVX. --- src/librustc_platform_intrinsics/lib.rs | 8 ++ src/librustc_platform_intrinsics/x86.rs | 152 ++++++++++++------------ 2 files changed, 87 insertions(+), 73 deletions(-) diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs index 1077a84c5a9f8..a7dfc188417d1 100755 --- a/src/librustc_platform_intrinsics/lib.rs +++ b/src/librustc_platform_intrinsics/lib.rs @@ -45,6 +45,14 @@ 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)); diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs index 32a8674460dac..cffcb5fa8be8a 100644 --- a/src/librustc_platform_intrinsics/x86.rs +++ b/src/librustc_platform_intrinsics/x86.rs @@ -18,82 +18,88 @@ macro_rules! p { } pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { - if !name.starts_with("mm_") { return None } + 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), - 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), - "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), - "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), - "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), - "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), - _ => return None - }) + "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), + _ => return None + }) + } else if name.starts_with("mm256_") { + Some(match &name["mm256_".len()..] { + _ => return None, + }) + } else { + None + } } From 29b79aabd8fb5855543ba41d684ddf2f3e43139c Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 10 Aug 2015 18:09:07 -0700 Subject: [PATCH 25/40] Add most AVX intrinsics. --- src/librustc_platform_intrinsics/x86.rs | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs index cffcb5fa8be8a..49b55dbc48754 100644 --- a/src/librustc_platform_intrinsics/x86.rs +++ b/src/librustc_platform_intrinsics/x86.rs @@ -93,10 +93,42 @@ pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { "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), _ => return None, }) } else { From 2a408ef6eee07b447b8b21f2233b01d3231c8f81 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 10 Aug 2015 18:30:33 -0700 Subject: [PATCH 26/40] Add most AVX2 intrinsics. --- src/librustc_platform_intrinsics/x86.rs | 51 +++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs index 49b55dbc48754..cab7ab2fecb82 100644 --- a/src/librustc_platform_intrinsics/x86.rs +++ b/src/librustc_platform_intrinsics/x86.rs @@ -129,6 +129,57 @@ pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { "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 { From d598bddc98f431ce92d9a3f33d7544ed637eda47 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Tue, 11 Aug 2015 09:55:16 -0700 Subject: [PATCH 27/40] Reorganise ARM intrinsic definitions. --- src/librustc_platform_intrinsics/arm.rs | 46 +++++++++++-------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/src/librustc_platform_intrinsics/arm.rs b/src/librustc_platform_intrinsics/arm.rs index ed1121b98df14..bc8740468890b 100644 --- a/src/librustc_platform_intrinsics/arm.rs +++ b/src/librustc_platform_intrinsics/arm.rs @@ -17,31 +17,27 @@ macro_rules! p { } } pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { - Some(match name { - "vpmax_u8" => p!("vpmaxu.v8i8", (i8x8, i8x8) -> i8x8), - "vpmax_s8" => p!("vpmaxs.v8i8", (i8x8, i8x8) -> i8x8), - "vpmax_u16" => p!("vpmaxu.v4i16", (i16x4, i16x4) -> i16x4), - "vpmax_s16" => p!("vpmaxs.v4i16", (i16x4, i16x4) -> i16x4), - "vpmax_u32" => p!("vpmaxu.v2i32", (i32x2, i32x2) -> i32x2), - "vpmax_s32" => p!("vpmaxs.v2i32", (i32x2, i32x2) -> i32x2), - - "vpmin_u8" => p!("vpminu.v8i8", (i8x8, i8x8) -> i8x8), - "vpmin_s8" => p!("vpmins.v8i8", (i8x8, i8x8) -> i8x8), - "vpmin_u16" => p!("vpminu.v4i16", (i16x4, i16x4) -> i16x4), - "vpmin_s16" => p!("vpmins.v4i16", (i16x4, i16x4) -> i16x4), - "vpmin_u32" => p!("vpminu.v2i32", (i32x2, i32x2) -> i32x2), - "vpmin_s32" => p!("vpmins.v2i32", (i32x2, i32x2) -> i32x2), - - "vsqrtq_f32" => plain!("llvm.sqrt.v4f32", (f32x4) -> f32x4), - "vsqrtq_f64" => plain!("llvm.sqrt.v2f64", (f64x2) -> f64x2), - - "vrecpeq_f32" => p!("vrecpe.v4f32", (f32x4) -> f32x4), - "vrsqrteq_f32" => p!("vrsqrte.v4f32", (f32x4) -> f32x4), - "vrsqrteq_f64" => p!("vrsqrte.v2f64", (f64x2) -> f64x2), - - "vmaxq_f32" => p!("vmaxs.v4f32", (f32x4, f32x4) -> f32x4), - - "vminq_f32" => p!("vmins.v4f32", (f32x4, f32x4) -> f32x4), + if !name.starts_with("v") { return None } + Some(match &name["v".len()..] { + "maxq_f32" => p!("vmaxs.v4f32", (f32x4, f32x4) -> f32x4), + "minq_f32" => p!("vmins.v4f32", (f32x4, f32x4) -> f32x4), + "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), + "recpeq_f32" => p!("vrecpe.v4f32", (f32x4) -> f32x4), + "rsqrteq_f32" => p!("vrsqrte.v4f32", (f32x4) -> f32x4), + "rsqrteq_f64" => p!("vrsqrte.v2f64", (f64x2) -> f64x2), + "sqrtq_f32" => plain!("llvm.sqrt.v4f32", (f32x4) -> f32x4), + "sqrtq_f64" => plain!("llvm.sqrt.v2f64", (f64x2) -> f64x2), _ => return None, }) } From 2115468f3363362e3c23b0aeb088cd8d39f6f2a6 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Tue, 11 Aug 2015 17:44:18 -0700 Subject: [PATCH 28/40] Add most ARM intrinsics. --- src/librustc_platform_intrinsics/arm.rs | 314 +++++++++++++++++++++++- src/librustc_platform_intrinsics/lib.rs | 1 + 2 files changed, 310 insertions(+), 5 deletions(-) diff --git a/src/librustc_platform_intrinsics/arm.rs b/src/librustc_platform_intrinsics/arm.rs index bc8740468890b..f29f7e384b4fb 100644 --- a/src/librustc_platform_intrinsics/arm.rs +++ b/src/librustc_platform_intrinsics/arm.rs @@ -19,8 +19,300 @@ macro_rules! p { pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { if !name.starts_with("v") { return None } Some(match &name["v".len()..] { + "sqrtq_f32" => plain!("llvm.sqrt.v4f32", (f32x4) -> f32x4), + "sqrtq_f64" => plain!("llvm.sqrt.v2f64", (f64x2) -> f64x2), + + "hadd_s8" => p!("vhadds.v8i8", (i8x8, i8x8) -> i8x8), + "haddq_s8" => p!("vhadds.v16i8", (i8x16, i8x16) -> i8x16), + "hadd_s16" => p!("vhadds.v4i16", (i16x4, i16x4) -> i16x4), + "haddq_s16" => p!("vhadds.v8i16", (i16x8, i16x8) -> i16x8), + "hadd_s32" => p!("vhadds.v2i32", (i32x2, i32x2) -> i32x2), + "haddq_s32" => p!("vhadds.v4i32", (i32x4, i32x4) -> i32x4), + "hadd_u8" => p!("vhaddu.v8i8", (i8x8, i8x8) -> i8x8), + "haddq_u8" => p!("vhaddu.v16i8", (i8x16, i8x16) -> i8x16), + "hadd_u16" => p!("vhaddu.v4i16", (i16x4, i16x4) -> i16x4), + "haddq_u16" => p!("vhaddu.v8i16", (i16x8, i16x8) -> i16x8), + "hadd_u32" => p!("vhaddu.v2i32", (i32x2, i32x2) -> i32x2), + "haddq_u32" => p!("vhaddu.v4i32", (i32x4, i32x4) -> i32x4), + "rhadd_s8" => p!("vrhadds.v8i8", (i8x8, i8x8) -> i8x8), + "rhaddq_s8" => p!("vrhadds.v16i8", (i8x16, i8x16) -> i8x16), + "rhadd_s16" => p!("vrhadds.v4i16", (i16x4, i16x4) -> i16x4), + "rhaddq_s16" => p!("vrhadds.v8i16", (i16x8, i16x8) -> i16x8), + "rhadd_s32" => p!("vrhadds.v2i32", (i32x2, i32x2) -> i32x2), + "rhaddq_s32" => p!("vrhadds.v4i32", (i32x4, i32x4) -> i32x4), + "rhadd_u8" => p!("vrhaddu.v8i8", (i8x8, i8x8) -> i8x8), + "rhaddq_u8" => p!("vrhaddu.v16i8", (i8x16, i8x16) -> i8x16), + "rhadd_u16" => p!("vrhaddu.v4i16", (i16x4, i16x4) -> i16x4), + "rhaddq_u16" => p!("vrhaddu.v8i16", (i16x8, i16x8) -> i16x8), + "rhadd_u32" => p!("vrhaddu.v2i32", (i32x2, i32x2) -> i32x2), + "rhaddq_u32" => p!("vrhaddu.v4i32", (i32x4, i32x4) -> i32x4), + "qadd_s8" => p!("vqadds.v8i8", (i8x8, i8x8) -> i8x8), + "qaddq_s8" => p!("vqadds.v16i8", (i8x16, i8x16) -> i8x16), + "qadd_s16" => p!("vqadds.v4i16", (i16x4, i16x4) -> i16x4), + "qaddq_s16" => p!("vqadds.v8i16", (i16x8, i16x8) -> i16x8), + "qadd_s32" => p!("vqadds.v2i32", (i32x2, i32x2) -> i32x2), + "qaddq_s32" => p!("vqadds.v4i32", (i32x4, i32x4) -> i32x4), + "qadd_s64" => p!("vqaddu.v1i64", (i64x1, i64x1) -> i64x1), + "qaddq_s64" => p!("vqaddu.v2i64", (i64x2, i64x2) -> i64x2), + "qadd_u8" => p!("vqaddu.v8i8", (i8x8, i8x8) -> i8x8), + "qaddq_u8" => p!("vqaddu.v16i8", (i8x16, i8x16) -> i8x16), + "qadd_u16" => p!("vqaddu.v4i16", (i16x4, i16x4) -> i16x4), + "qaddq_u16" => p!("vqaddu.v8i16", (i16x8, i16x8) -> i16x8), + "qadd_u32" => p!("vqaddu.v2i32", (i32x2, i32x2) -> i32x2), + "qaddq_u32" => p!("vqaddu.v4i32", (i32x4, i32x4) -> i32x4), + "qadd_u64" => p!("vqaddu.v1i64", (i64x1, i64x1) -> i64x1), + "qaddq_u64" => p!("vqaddu.v2i64", (i64x2, i64x2) -> i64x2), + "raddhn_s16" => p!("vraddhn.v8i8", (i16x8, i16x8) -> i8x8), + "raddhn_s32" => p!("vraddhn.v4i16", (i32x4, i32x4) -> i16x4), + "raddhn_s64" => p!("vraddhn.v2i32", (i64x2, i64x2) -> i32x2), + "fma_f32" => plain!("llvm.fma.v2f32", (f32x2, f32x2, f32x2) -> f32x2), + "fmaq_f32" => plain!("llvm.fma.v4f32", (f32x4, f32x4, f32x4) -> f32x4), + "qdmulh_s16" => p!("vqdmulh.v4i16", (i16x4, i16x4) -> i16x4), + "qdmulhq_s16" => p!("vqdmulh.v8i16", (i16x8, i16x8) -> i16x8), + "qdmulh_s32" => p!("vqdmulh.v2i32", (i32x2, i32x2) -> i32x4), + "qdmulhq_s32" => p!("vqdmulh.v4i32", (i32x4, i32x4) -> i32x4), + "qrdmulh_s16" => p!("vqrdmulh.v4i16", (i16x4, i16x4) -> i16x4), + "qrdmulhqr_s16" => p!("vqrdmulh.v8i16", (i16x8, i16x8) -> i16x8), + "qrdmulh_s32" => p!("vqrdmulh.v2i32", (i32x2, i32x2) -> i32x4), + "qrdmulhqr_s32" => p!("vqrdmulh.v4i32", (i32x4, i32x4) -> i32x4), + "mull_s8" => p!("vmulls.v8i16", (i8x8, i8x8) -> i16x8), + "mull_s16" => p!("vmulls.v4i32", (i16x4, i16x4) -> i32x4), + "mull_s32" => p!("vmulls.v2i64", (i32x2, i32x2) -> i64x2), + "mull_u8" => p!("vmullu.v8i16", (i8x8, i8x8) -> i16x8), + "mull_u16" => p!("vmullu.v4i32", (i16x4, i16x4) -> i32x4), + "mull_u32" => p!("vmullu.v2i64", (i32x2, i32x2) -> i64x2), + "qdmull_s16" => p!("vqdmull.v4i32", (i16x4, i16x4) -> i32x4), + "qdmull_s32" => p!("vqdmull.v2i64", (i32x2, i32x2) -> i64x2), + "hsub_s8" => p!("vhsubs.v8i8", (i8x8, i8x8) -> i8x8), + "hsubq_s8" => p!("vhsubs.v16i8", (i8x16, i8x16) -> i8x16), + "hsub_s16" => p!("vhsubs.v4i16", (i16x4, i16x4) -> i16x4), + "hsubq_s16" => p!("vhsubs.v8i16", (i16x8, i16x8) -> i16x8), + "hsub_s32" => p!("vhsubs.v2i32", (i32x2, i32x2) -> i32x2), + "hsubq_s32" => p!("vhsubs.v4i32", (i32x4, i32x4) -> i32x4), + "hsub_u8" => p!("vhsubu.v8i8", (i8x8, i8x8) -> i8x8), + "hsubq_u8" => p!("vhsubu.v16i8", (i8x16, i8x16) -> i8x16), + "hsub_u16" => p!("vhsubu.v4i16", (i16x4, i16x4) -> i16x4), + "hsubq_u16" => p!("vhsubu.v8i16", (i16x8, i16x8) -> i16x8), + "hsub_u32" => p!("vhsubu.v2i32", (i32x2, i32x2) -> i32x2), + "hsubq_u32" => p!("vhsubu.v4i32", (i32x4, i32x4) -> i32x4), + "qsub_s8" => p!("vqsubs.v8i8", (i8x8, i8x8) -> i8x8), + "qsubq_s8" => p!("vqsubs.v16i8", (i8x16, i8x16) -> i8x16), + "qsub_s16" => p!("vqsubs.v4i16", (i16x4, i16x4) -> i16x4), + "qsubq_s16" => p!("vqsubs.v8i16", (i16x8, i16x8) -> i16x8), + "qsub_s32" => p!("vqsubs.v2i32", (i32x2, i32x2) -> i32x2), + "qsubq_s32" => p!("vqsubs.v4i32", (i32x4, i32x4) -> i32x4), + "qsub_s64" => p!("vqsubu.v1i64", (i64x1, i64x1) -> i64x1), + "qsubq_s64" => p!("vqsubu.v2i64", (i64x2, i64x2) -> i64x2), + "qsub_u8" => p!("vqsubu.v8i8", (i8x8, i8x8) -> i8x8), + "qsubq_u8" => p!("vqsubu.v16i8", (i8x16, i8x16) -> i8x16), + "qsub_u16" => p!("vqsubu.v4i16", (i16x4, i16x4) -> i16x4), + "qsubq_u16" => p!("vqsubu.v8i16", (i16x8, i16x8) -> i16x8), + "qsub_u32" => p!("vqsubu.v2i32", (i32x2, i32x2) -> i32x2), + "qsubq_u32" => p!("vqsubu.v4i32", (i32x4, i32x4) -> i32x4), + "qsub_u64" => p!("vqsubu.v1i64", (i64x1, i64x1) -> i64x1), + "qsubq_u64" => p!("vqsubu.v2i64", (i64x2, i64x2) -> i64x2), + "abd_s8" => p!("vabds.v8i8", (i8x8, i8x8) -> i8x8), + "abdq_s8" => p!("vabds.v16i8", (i8x16, i8x16) -> i8x16), + "abd_s16" => p!("vabds.v4i16", (i16x4, i16x4) -> i16x4), + "abdq_s16" => p!("vabds.v8i16", (i16x8, i16x8) -> i16x8), + "abd_s32" => p!("vabds.v2i32", (i32x2, i32x2) -> i32x2), + "abdq_s32" => p!("vabds.v4i32", (i32x4, i32x4) -> i32x4), + "abd_u8" => p!("vabdu.v8i8", (i8x8, i8x8) -> i8x8), + "abdq_u8" => p!("vabdu.v16i8", (i8x16, i8x16) -> i8x16), + "abd_u16" => p!("vabdu.v4i16", (i16x4, i16x4) -> i16x4), + "abdq_u16" => p!("vabdu.v8i16", (i16x8, i16x8) -> i16x8), + "abd_u32" => p!("vabdu.v2i32", (i32x2, i32x2) -> i32x2), + "abdq_u32" => p!("vabdu.v4i32", (i32x4, i32x4) -> i32x4), + "abd_f32" => p!("vabds.v2f32", (f32x2, f32x2) -> f32x2), + "abdq_f32" => p!("vabds.v4f32", (f32x4, f32x4) -> f32x4), + "max_s8" => p!("vmaxs.v8i8", (i8x8, i8x8) -> i8x8), + "maxq_s8" => p!("vmaxs.v16i8", (i8x16, i8x16) -> i8x16), + "max_s16" => p!("vmaxs.v4i16", (i16x4, i16x4) -> i16x4), + "maxq_s16" => p!("vmaxs.v8i16", (i16x8, i16x8) -> i16x8), + "max_s32" => p!("vmaxs.v2i32", (i32x2, i32x2) -> i32x2), + "maxq_s32" => p!("vmaxs.v4i32", (i32x4, i32x4) -> i32x4), + "max_u8" => p!("vmaxu.v8i8", (i8x8, i8x8) -> i8x8), + "maxq_u8" => p!("vmaxu.v16i8", (i8x16, i8x16) -> i8x16), + "max_u16" => p!("vmaxu.v4i16", (i16x4, i16x4) -> i16x4), + "maxq_u16" => p!("vmaxu.v8i16", (i16x8, i16x8) -> i16x8), + "max_u32" => p!("vmaxu.v2i32", (i32x2, i32x2) -> i32x2), + "maxq_u32" => p!("vmaxu.v4i32", (i32x4, i32x4) -> i32x4), + "max_f32" => p!("vmaxs.v2f32", (f32x2, f32x2) -> f32x2), "maxq_f32" => p!("vmaxs.v4f32", (f32x4, f32x4) -> f32x4), + "min_s8" => p!("vmins.v8i8", (i8x8, i8x8) -> i8x8), + "minq_s8" => p!("vmins.v16i8", (i8x16, i8x16) -> i8x16), + "min_s16" => p!("vmins.v4i16", (i16x4, i16x4) -> i16x4), + "minq_s16" => p!("vmins.v8i16", (i16x8, i16x8) -> i16x8), + "min_s32" => p!("vmins.v2i32", (i32x2, i32x2) -> i32x2), + "minq_s32" => p!("vmins.v4i32", (i32x4, i32x4) -> i32x4), + "min_u8" => p!("vminu.v8i8", (i8x8, i8x8) -> i8x8), + "minq_u8" => p!("vminu.v16i8", (i8x16, i8x16) -> i8x16), + "min_u16" => p!("vminu.v4i16", (i16x4, i16x4) -> i16x4), + "minq_u16" => p!("vminu.v8i16", (i16x8, i16x8) -> i16x8), + "min_u32" => p!("vminu.v2i32", (i32x2, i32x2) -> i32x2), + "minq_u32" => p!("vminu.v4i32", (i32x4, i32x4) -> i32x4), + "min_f32" => p!("vmins.v2f32", (f32x2, f32x2) -> f32x2), "minq_f32" => p!("vmins.v4f32", (f32x4, f32x4) -> f32x4), + "shl_s8" => p!("vshifts.v8i8", (i8x8, i8x8) -> i8x8), + "shlq_s8" => p!("vshifts.v16i8", (i8x16, i8x16) -> i8x16), + "shl_s16" => p!("vshifts.v4i16", (i16x4, i16x4) -> i16x4), + "shlq_s16" => p!("vshifts.v8i16", (i16x8, i16x8) -> i16x8), + "shl_s32" => p!("vshifts.v2i32", (i32x2, i32x2) -> i32x2), + "shlq_s32" => p!("vshifts.v4i32", (i32x4, i32x4) -> i32x4), + "shl_s64" => p!("vshiftu.v1i64", (i64x1, i64x1) -> i64x1), + "shlq_s64" => p!("vshiftu.v2i64", (i64x2, i64x2) -> i64x2), + "shl_u8" => p!("vshiftu.v8i8", (i8x8, i8x8) -> i8x8), + "shlq_u8" => p!("vshiftu.v16i8", (i8x16, i8x16) -> i8x16), + "shl_u16" => p!("vshiftu.v4i16", (i16x4, i16x4) -> i16x4), + "shlq_u16" => p!("vshiftu.v8i16", (i16x8, i16x8) -> i16x8), + "shl_u32" => p!("vshiftu.v2i32", (i32x2, i32x2) -> i32x2), + "shlq_u32" => p!("vshiftu.v4i32", (i32x4, i32x4) -> i32x4), + "shl_u64" => p!("vshiftu.v1i64", (i64x1, i64x1) -> i64x1), + "shlq_u64" => p!("vshiftu.v2i64", (i64x2, i64x2) -> i64x2), + "qshl_s8" => p!("vqshifts.v8i8", (i8x8, i8x8) -> i8x8), + "qshlq_s8" => p!("vqshifts.v16i8", (i8x16, i8x16) -> i8x16), + "qshl_s16" => p!("vqshifts.v4i16", (i16x4, i16x4) -> i16x4), + "qshlq_s16" => p!("vqshifts.v8i16", (i16x8, i16x8) -> i16x8), + "qshl_s32" => p!("vqshifts.v2i32", (i32x2, i32x2) -> i32x2), + "qshlq_s32" => p!("vqshifts.v4i32", (i32x4, i32x4) -> i32x4), + "qshl_s64" => p!("vqshiftu.v1i64", (i64x1, i64x1) -> i64x1), + "qshlq_s64" => p!("vqshiftu.v2i64", (i64x2, i64x2) -> i64x2), + "qshl_u8" => p!("vqshiftu.v8i8", (i8x8, i8x8) -> i8x8), + "qshlq_u8" => p!("vqshiftu.v16i8", (i8x16, i8x16) -> i8x16), + "qshl_u16" => p!("vqshiftu.v4i16", (i16x4, i16x4) -> i16x4), + "qshlq_u16" => p!("vqshiftu.v8i16", (i16x8, i16x8) -> i16x8), + "qshl_u32" => p!("vqshiftu.v2i32", (i32x2, i32x2) -> i32x2), + "qshlq_u32" => p!("vqshiftu.v4i32", (i32x4, i32x4) -> i32x4), + "qshl_u64" => p!("vqshiftu.v1i64", (i64x1, i64x1) -> i64x1), + "qshlq_u64" => p!("vqshiftu.v2i64", (i64x2, i64x2) -> i64x2), + "rshl_s8" => p!("vrshifts.v8i8", (i8x8, i8x8) -> i8x8), + "rshlr_s8" => p!("vrshifts.v16i8", (i8x16, i8x16) -> i8x16), + "rshl_s16" => p!("vrshifts.v4i16", (i16x4, i16x4) -> i16x4), + "rshlr_s16" => p!("vrshifts.v8i16", (i16x8, i16x8) -> i16x8), + "rshl_s32" => p!("vrshifts.v2i32", (i32x2, i32x2) -> i32x2), + "rshlr_s32" => p!("vrshifts.v4i32", (i32x4, i32x4) -> i32x4), + "rshl_s64" => p!("vrshiftu.v1i64", (i64x1, i64x1) -> i64x1), + "rshlr_s64" => p!("vrshiftu.v2i64", (i64x2, i64x2) -> i64x2), + "rshl_u8" => p!("vrshiftu.v8i8", (i8x8, i8x8) -> i8x8), + "rshlr_u8" => p!("vrshiftu.v16i8", (i8x16, i8x16) -> i8x16), + "rshl_u16" => p!("vrshiftu.v4i16", (i16x4, i16x4) -> i16x4), + "rshlr_u16" => p!("vrshiftu.v8i16", (i16x8, i16x8) -> i16x8), + "rshl_u32" => p!("vrshiftu.v2i32", (i32x2, i32x2) -> i32x2), + "rshlr_u32" => p!("vrshiftu.v4i32", (i32x4, i32x4) -> i32x4), + "rshl_u64" => p!("vrshiftu.v1i64", (i64x1, i64x1) -> i64x1), + "rshlr_u64" => p!("vrshiftu.v2i64", (i64x2, i64x2) -> i64x2), + "qrshl_s8" => p!("vqrshifts.v8i8", (i8x8, i8x8) -> i8x8), + "qrshlqr_s8" => p!("vqrshifts.v16i8", (i8x16, i8x16) -> i8x16), + "qrshl_s16" => p!("vqrshifts.v4i16", (i16x4, i16x4) -> i16x4), + "qrshlqr_s16" => p!("vqrshifts.v8i16", (i16x8, i16x8) -> i16x8), + "qrshl_s32" => p!("vqrshifts.v2i32", (i32x2, i32x2) -> i32x2), + "qrshlqr_s32" => p!("vqrshifts.v4i32", (i32x4, i32x4) -> i32x4), + "qrshl_s64" => p!("vqrshiftu.v1i64", (i64x1, i64x1) -> i64x1), + "qrshlqr_s64" => p!("vqrshiftu.v2i64", (i64x2, i64x2) -> i64x2), + "qrshl_u8" => p!("vqrshiftu.v8i8", (i8x8, i8x8) -> i8x8), + "qrshlqr_u8" => p!("vqrshiftu.v16i8", (i8x16, i8x16) -> i8x16), + "qrshl_u16" => p!("vqrshiftu.v4i16", (i16x4, i16x4) -> i16x4), + "qrshlqr_u16" => p!("vqrshiftu.v8i16", (i16x8, i16x8) -> i16x8), + "qrshl_u32" => p!("vqrshiftu.v2i32", (i32x2, i32x2) -> i32x2), + "qrshlqr_u32" => p!("vqrshiftu.v4i32", (i32x4, i32x4) -> i32x4), + "qrshl_u64" => p!("vqrshiftu.v1i64", (i64x1, i64x1) -> i64x1), + "qrshlqr_u64" => p!("vqrshiftu.v2i64", (i64x2, i64x2) -> i64x2), + "qmovn_s16" => p!("vqmovns.v8i8", (i16x8) -> i8x8), + "qmovn_s32" => p!("vqmovns.v4i16", (i32x4) -> i16x4), + "qmovn_s64" => p!("vqmovns.v2i32", (i64x2) -> i32x2), + "qmovn_u16" => p!("vqmovnu.v8i8", (i16x8) -> i8x8), + "qmovn_u32" => p!("vqmovnu.v4i16", (i32x4) -> i16x4), + "qmovn_u64" => p!("vqmovnu.v2i32", (i64x2) -> i32x2), + "qmovun_s16" => p!("vqmovnsu.v8i8", (i16x8) -> i8x8), + "qmovun_s32" => p!("vqmovnsu.v4i16", (i32x4) -> i16x4), + "qmovun_s64" => p!("vqmovnsu.v2i32", (i64x2) -> i32x2), + "abs_s8" => p!("vabs.v8i8", (i8x8, i8x8) -> i8x8), + "absq_s8" => p!("vabs.v16i8", (i8x16, i8x16) -> i8x16), + "abs_s16" => p!("vabs.v4i16", (i16x4, i16x4) -> i16x4), + "absq_s16" => p!("vabs.v8i16", (i16x8, i16x8) -> i16x8), + "abs_s32" => p!("vabs.v2i32", (i32x2, i32x2) -> i32x2), + "absq_s32" => p!("vabs.v4i32", (i32x4, i32x4) -> i32x4), + "abs_f32" => p!("vabs.v2f32", (f32x2, f32x2) -> f32x2), + "absq_f32" => p!("vabs.v4f32", (f32x4, f32x4) -> f32x4), + "qabs_s8" => p!("vqabs.v8i8", (i8x8, i8x8) -> i8x8), + "qabsq_s8" => p!("vqabs.v16i8", (i8x16, i8x16) -> i8x16), + "qabs_s16" => p!("vqabs.v4i16", (i16x4, i16x4) -> i16x4), + "qabsq_s16" => p!("vqabs.v8i16", (i16x8, i16x8) -> i16x8), + "qabs_s32" => p!("vqabs.v2i32", (i32x2, i32x2) -> i32x2), + "qabsq_s32" => p!("vqabs.v4i32", (i32x4, i32x4) -> i32x4), + "neg_s8" => p!("vneg.v8i8", (i8x8) -> i8x8), + "negq_s8" => p!("vneg.v16i8", (i8x16) -> i8x16), + "neg_s16" => p!("vneg.v4i16", (i16x4) -> i16x4), + "negq_s16" => p!("vneg.v8i16", (i16x8) -> i16x8), + "neg_s32" => p!("vneg.v2i32", (i32x2) -> i32x2), + "negq_s32" => p!("vneg.v4i32", (i32x4) -> i32x4), + "neg_f32" => p!("vneg.v2f32", (f32x2) -> f32x2), + "negq_f32" => p!("vneg.v4f32", (f32x4) -> f32x4), + "qneg_s8" => p!("vqneg.v8i8", (i8x8) -> i8x8), + "qnegq_s8" => p!("vqneg.v16i8", (i8x16) -> i8x16), + "qneg_s16" => p!("vqneg.v4i16", (i16x4) -> i16x4), + "qnegq_s16" => p!("vqneg.v8i16", (i16x8) -> i16x8), + "qneg_s32" => p!("vqneg.v2i32", (i32x2) -> i32x2), + "qnegq_s32" => p!("vqneg.v4i32", (i32x4) -> i32x4), + "cls_s8" => p!("vcls.v8i8", (i8x8) -> i8x8), + "clsq_s8" => p!("vcls.v16i8", (i8x16) -> i8x16), + "cls_s16" => p!("vcls.v4i16", (i16x4) -> i16x4), + "clsq_s16" => p!("vcls.v8i16", (i16x8) -> i16x8), + "cls_s32" => p!("vcls.v2i32", (i32x2) -> i32x2), + "clsq_s32" => p!("vcls.v4i32", (i32x4) -> i32x4), + "clz_s8" => p!("vclz.v8i8", (i8x8) -> i8x8), + "clzq_s8" => p!("vclz.v16i8", (i8x16) -> i8x16), + "clz_s16" => p!("vclz.v4i16", (i16x4) -> i16x4), + "clzq_s16" => p!("vclz.v8i16", (i16x8) -> i16x8), + "clz_s32" => p!("vclz.v2i32", (i32x2) -> i32x2), + "clzq_s32" => p!("vclz.v4i32", (i32x4) -> i32x4), + "cnt_s8" => p!("vcnt.v8i8", (i8x8) -> i8x8), + "cntq_s8" => p!("vcnt.v16i8", (i8x16) -> i8x16), + "recpe_u32" => p!("vrecpe.v2i32", (i32x2) -> i32x2), + "recpeq_u32" => p!("vrecpe.v4i32", (i32x4) -> i32x4), + "recpe_f32" => p!("vrecpe.v2f32", (f32x2) -> f32x2), + "recpeq_f32" => p!("vrecpe.v4f32", (f32x4) -> f32x4), + "recps_f32" => p!("vrecps.v2f32", (f32x2, f32x2) -> f32x2), + "recpsq_f32" => p!("vrecps.v4f32", (f32x4, f32x4) -> f32x4), + "rsqrte_u32" => p!("vrsqrte.v2i32", (i32x2) -> i32x2), + "rsqrteq_u32" => p!("vrsqrte.v4i32", (i32x4) -> i32x4), + "rsqrte_f32" => p!("vrsqrte.v2f32", (f32x2) -> f32x2), + "rsqrteq_f32" => p!("vrsqrte.v4f32", (f32x4) -> f32x4), + "rsqrts_f32" => p!("vrsqrts.v2f32", (f32x2, f32x2) -> f32x2), + "rsqrtsq_f32" => p!("vrsqrts.v4f32", (f32x4, f32x4) -> f32x4), + "bsl_s8" => p!("vsl.v8i8", (i8x8, i8x8, i8x8) -> i8x8), + "bslq_s8" => p!("vsl.v16i8", (i8x16, i8x16, i8x16) -> i8x16), + "padd_s8" => p!("vpadd.v8i8", (i8x8, i8x8) -> i8x8), + "padd_s16" => p!("vpadd.v4i16", (i16x4, i16x4) -> i16x4), + "padd_s32" => p!("vpadd.v2i32", (i32x2, i32x2) -> i32x2), + "padd_u8" => p!("vpadd.v8i8", (i8x8, i8x8) -> i8x8), + "padd_u16" => p!("vpadd.v4i16", (i16x4, i16x4) -> i16x4), + "padd_u32" => p!("vpadd.v2i32", (i32x2, i32x2) -> i32x2), + "padd_f32" => p!("vpadd.v2f32", (f32x2, f32x2) -> f32x2), + "paddl_s8" => p!("vpaddls.v4i16.v8i8", (i8x8) -> i16x4), + "paddlq_s8" => p!("vpaddls.v8i16.v16i8", (i8x16) -> i16x8), + "paddl_s16" => p!("vpaddls.v2i32.v4i16", (i16x4) -> i32x2), + "paddlq_s16" => p!("vpaddls.v4i32.v8i16", (i16x8) -> i32x4), + "paddl_s32" => p!("vpaddls.v1i64.v2i32", (i32x2) -> i64x1), + "paddlq_s32" => p!("vpaddls.v2i64.v4i32", (i32x4) -> i64x2), + "paddl_u8" => p!("vpaddlu.v4i16.v8i8", (i8x8) -> i16x4), + "paddlq_u8" => p!("vpaddlu.v8i16.v16i8", (i8x16) -> i16x8), + "paddl_u16" => p!("vpaddlu.v2i32.v4i16", (i16x4) -> i32x2), + "paddlq_u16" => p!("vpaddlu.v4i32.v8i16", (i16x8) -> i32x4), + "paddl_u32" => p!("vpaddlu.v1i64.v2i32", (i32x2) -> i64x1), + "paddlq_u32" => p!("vpaddlu.v2i64.v4i32", (i32x4) -> i64x2), + "padal_s8" => p!("vpadals.v4i16.v8i8", (i16x4, i8x8) -> i16x4), + "padalq_s8" => p!("vpadals.v8i16.v16i8", (i16x8, i8x16) -> i16x8), + "padal_s16" => p!("vpadals.v2i32.v4i16", (i32x2, i16x4) -> i32x2), + "padalq_s16" => p!("vpadals.v4i32.v8i16", (i32x4, i16x8) -> i32x4), + "padal_s32" => p!("vpadals.v1i64.v2i32", (i64x1, i32x2) -> i64x1), + "padalq_s32" => p!("vpadals.v2i64.v4i32", (i64x2, i32x4) -> i64x2), + "padal_u8" => p!("vpadalu.v4i16.v8i8", (i16x4, i8x8) -> i16x4), + "padalq_u8" => p!("vpadalu.v8i16.v16i8", (i16x8, i8x16) -> i16x8), + "padal_u16" => p!("vpadalu.v2i32.v4i16", (i32x2, i16x4) -> i32x2), + "padalq_u16" => p!("vpadalu.v4i32.v8i16", (i32x4, i16x8) -> i32x4), + "padal_u32" => p!("vpadalu.v1i64.v2i32", (i64x1, i32x2) -> i64x1), + "padalq_u32" => p!("vpadalu.v2i64.v4i32", (i64x2, i32x4) -> i64x2), "pmax_s16" => p!("vpmaxs.v4i16", (i16x4, i16x4) -> i16x4), "pmax_s32" => p!("vpmaxs.v2i32", (i32x2, i32x2) -> i32x2), "pmax_s8" => p!("vpmaxs.v8i8", (i8x8, i8x8) -> i8x8), @@ -33,11 +325,23 @@ pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { "pmin_u16" => p!("vpminu.v4i16", (i16x4, i16x4) -> i16x4), "pmin_u32" => p!("vpminu.v2i32", (i32x2, i32x2) -> i32x2), "pmin_u8" => p!("vpminu.v8i8", (i8x8, i8x8) -> i8x8), - "recpeq_f32" => p!("vrecpe.v4f32", (f32x4) -> f32x4), - "rsqrteq_f32" => p!("vrsqrte.v4f32", (f32x4) -> f32x4), - "rsqrteq_f64" => p!("vrsqrte.v2f64", (f64x2) -> f64x2), - "sqrtq_f32" => plain!("llvm.sqrt.v4f32", (f32x4) -> f32x4), - "sqrtq_f64" => plain!("llvm.sqrt.v2f64", (f64x2) -> f64x2), + "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 index a7dfc188417d1..134b4c66419b6 100755 --- a/src/librustc_platform_intrinsics/lib.rs +++ b/src/librustc_platform_intrinsics/lib.rs @@ -65,6 +65,7 @@ macro_rules! ty { (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)); From 1f5739fb3cdaff001d1af138a7b9b096a06c94e8 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 12 Aug 2015 11:25:37 -0700 Subject: [PATCH 29/40] Switch shuffle intrinsics to arrays of indices. Format: fn shuffle_simdNNN(x: T, y: T, idx: [u32; NNN]) -> U; --- src/librustc_trans/trans/intrinsic.rs | 51 ++++++++++++++++++-------- src/librustc_typeck/check/intrinsic.rs | 5 +-- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 735d5d224845e..e076e376b0907 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -12,6 +12,7 @@ use arena::TypedArena; use intrinsics::{self, Intrinsic}; +use libc; use llvm; use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef, TypeKind}; use middle::subst; @@ -24,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; @@ -38,6 +40,7 @@ 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; pub fn get_simple_intrinsic(ccx: &CrateContext, item: &ast::ForeignItem) -> Option { @@ -343,6 +346,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, @@ -805,6 +815,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, generic_simd_intrinsic(bcx, name, substs, callee_ty, + expr_arguments, &llargs, ret_ty, llret_ty, call_debug_location, @@ -1307,15 +1318,18 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, return rust_try } -fn generic_simd_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - name: &str, - _substs: subst::Substs<'tcx>, - callee_ty: Ty<'tcx>, - llargs: &[ValueRef], - ret_ty: Ty<'tcx>, - llret_ty: Type, - call_debug_location: DebugLoc, - call_info: NodeIdAndSpan) -> ValueRef { +fn generic_simd_intrinsic<'blk, 'tcx, 'a> + (bcx: Block<'blk, 'tcx>, + name: &str, + substs: subst::Substs<'tcx>, + callee_ty: Ty<'tcx>, + args: Option<&[P]>, + llargs: &[ValueRef], + ret_ty: Ty<'tcx>, + llret_ty: Type, + call_debug_location: DebugLoc, + call_info: NodeIdAndSpan) -> ValueRef +{ let tcx = bcx.tcx(); let arg_tys = match callee_ty.sty { ty::TyBareFn(_, ref f) => { @@ -1376,7 +1390,6 @@ fn generic_simd_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Err(_) => tcx.sess.span_bug(call_info.span, "bad `simd_shuffle` instruction only caught in trans?") }; - assert_eq!(llargs.len(), 2 + n); require!(arg_tys[0] == arg_tys[1], "SIMD shuffle intrinsic monomorphised with different input types"); @@ -1394,12 +1407,18 @@ fn generic_simd_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let total_len = in_len as u64 * 2; - let indices: Option> = llargs[2..] - .iter() - .enumerate() - .map(|(i, val)| { - let arg_idx = i + 2; - let c = const_to_opt_uint(*val); + let vector = match args { + Some(args) => &args[2], + None => bcx.sess().span_bug(call_info.span, + "intrinsic call with unexpected argument shape"), + }; + let vector = consts::const_expr(bcx.ccx(), vector, tcx.mk_substs(substs), None).0; + + let indices: Option> = (0..n) + .map(|i| { + let arg_idx = i; + let val = const_get_elt(bcx.ccx(), vector, &[i as libc::c_uint]); + let c = const_to_opt_uint(val); match c { None => { bcx.sess().span_err(call_info.span, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 0df497877ae17..8b5fbcd02f552 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -21,7 +21,6 @@ use middle::ty_fold::TypeFolder; use {CrateCtxt, require_same_types}; use std::collections::{HashMap}; -use std::iter; use syntax::abi; use syntax::attr::AttrMetaMethods; use syntax::ast; @@ -387,8 +386,8 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, name if name.starts_with("simd_shuffle") => { match name["simd_shuffle".len()..].parse() { Ok(n) => { - let mut params = vec![param(0), param(0)]; - params.extend(iter::repeat(tcx.types.u32).take(n)); + let params = vec![param(0), param(0), + tcx.mk_ty(ty::TyArray(tcx.types.u32, n))]; let ictxt = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); let ret = ictxt.next_ty_var(); From 8b68f58fef4ffb833c123f057638484fa59ded76 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 12 Aug 2015 15:37:21 -0700 Subject: [PATCH 30/40] Allow generic repr(simd) types. Absolute correctness is checked at monomorphisation time. --- src/librustc_trans/trans/type_of.rs | 16 ++++++++++++++-- src/librustc_typeck/check/mod.rs | 16 ++++++++-------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 3edd4530ceb69..2e2f11bd133d8 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -224,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) @@ -410,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) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 500e4287d61b8..a16415a03c0f1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4321,10 +4321,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; @@ -4337,10 +4333,14 @@ pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) { span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous"); return; } - if !e.is_machine() { - span_err!(tcx.sess, sp, E0077, - "SIMD vector element type should be machine type"); - return; + match e.sty { + ty::TyParam(_) => { /* struct(T, T, T, T) is ok */ } + _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ } + _ => { + span_err!(tcx.sess, sp, E0077, + "SIMD vector element type should be machine type"); + return; + } } } _ => () From 3e500673cc540828f9ec609f83d07f4e1c271de0 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 12 Aug 2015 16:09:02 -0700 Subject: [PATCH 31/40] Fix existing tests for new `#[repr(simd)]`. --- .../compile-fail/feature-gate-simd-ffi.rs | 6 +- src/test/compile-fail/gated-simd.rs | 14 -- src/test/compile-fail/simd-binop.rs | 37 ----- src/test/compile-fail/simd-type.rs | 11 +- src/test/run-fail/overflowing-simd-lsh-1.rs | 23 --- src/test/run-fail/overflowing-simd-lsh-2.rs | 23 --- src/test/run-fail/overflowing-simd-lsh-3.rs | 23 --- src/test/run-fail/overflowing-simd-lsh-4.rs | 49 ------ src/test/run-fail/overflowing-simd-rsh-1.rs | 23 --- src/test/run-fail/overflowing-simd-rsh-2.rs | 23 --- src/test/run-fail/overflowing-simd-rsh-3.rs | 23 --- src/test/run-fail/overflowing-simd-rsh-4.rs | 49 ------ src/test/run-make/simd-ffi/simd.rs | 6 +- src/test/run-pass/issue-17170.rs | 4 +- src/test/run-pass/issue-23037.rs | 19 --- src/test/run-pass/issue-24258.rs | 26 --- src/test/run-pass/simd-binop.rs | 76 --------- src/test/run-pass/simd-generics.rs | 10 +- src/test/run-pass/simd-shift-near-oflo.rs | 154 ------------------ src/test/run-pass/simd-size-align.rs | 44 ++--- src/test/run-pass/simd-type.rs | 4 +- 21 files changed, 43 insertions(+), 604 deletions(-) delete mode 100644 src/test/compile-fail/gated-simd.rs delete mode 100644 src/test/compile-fail/simd-binop.rs delete mode 100644 src/test/run-fail/overflowing-simd-lsh-1.rs delete mode 100644 src/test/run-fail/overflowing-simd-lsh-2.rs delete mode 100644 src/test/run-fail/overflowing-simd-lsh-3.rs delete mode 100644 src/test/run-fail/overflowing-simd-lsh-4.rs delete mode 100644 src/test/run-fail/overflowing-simd-rsh-1.rs delete mode 100644 src/test/run-fail/overflowing-simd-rsh-2.rs delete mode 100644 src/test/run-fail/overflowing-simd-rsh-3.rs delete mode 100644 src/test/run-fail/overflowing-simd-rsh-4.rs delete mode 100644 src/test/run-pass/issue-23037.rs delete mode 100644 src/test/run-pass/issue-24258.rs delete mode 100644 src/test/run-pass/simd-binop.rs delete mode 100644 src/test/run-pass/simd-shift-near-oflo.rs diff --git a/src/test/compile-fail/feature-gate-simd-ffi.rs b/src/test/compile-fail/feature-gate-simd-ffi.rs index 32c50b1b8c159..f7bd2fcbceb4f 100644 --- a/src/test/compile-fail/feature-gate-simd-ffi.rs +++ b/src/test/compile-fail/feature-gate-simd-ffi.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(simd, core_simd)] -#![allow(dead_code)] +#![feature(repr_simd, core_simd)] +#![allow(dead_code, deprecated)] use std::simd::f32x4; -#[simd] #[derive(Copy, Clone)] #[repr(C)] struct LocalSimd(u8, u8); +#[repr(simd)] #[derive(Copy, Clone)] #[repr(C)] struct LocalSimd(u8, u8); extern { fn foo() -> f32x4; //~ ERROR use of SIMD type diff --git a/src/test/compile-fail/gated-simd.rs b/src/test/compile-fail/gated-simd.rs deleted file mode 100644 index 59c44bff3c79d..0000000000000 --- a/src/test/compile-fail/gated-simd.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[simd] -pub struct i64x2(i64, i64); //~ ERROR: SIMD types are experimental - -fn main() {} diff --git a/src/test/compile-fail/simd-binop.rs b/src/test/compile-fail/simd-binop.rs deleted file mode 100644 index feffe5c0b06c8..0000000000000 --- a/src/test/compile-fail/simd-binop.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-tidy-linelength - -#![feature(core)] - -use std::simd::f32x4; - -fn main() { - - let _ = f32x4(0.0, 0.0, 0.0, 0.0) == f32x4(0.0, 0.0, 0.0, 0.0); - //~^ ERROR binary comparison operation `==` not supported for floating point SIMD vector `core::simd::f32x4` - - let _ = f32x4(0.0, 0.0, 0.0, 0.0) != f32x4(0.0, 0.0, 0.0, 0.0); - //~^ ERROR binary comparison operation `!=` not supported for floating point SIMD vector `core::simd::f32x4` - - let _ = f32x4(0.0, 0.0, 0.0, 0.0) < f32x4(0.0, 0.0, 0.0, 0.0); - //~^ ERROR binary comparison operation `<` not supported for floating point SIMD vector `core::simd::f32x4` - - let _ = f32x4(0.0, 0.0, 0.0, 0.0) <= f32x4(0.0, 0.0, 0.0, 0.0); - //~^ ERROR binary comparison operation `<=` not supported for floating point SIMD vector `core::simd::f32x4` - - let _ = f32x4(0.0, 0.0, 0.0, 0.0) >= f32x4(0.0, 0.0, 0.0, 0.0); - //~^ ERROR binary comparison operation `>=` not supported for floating point SIMD vector `core::simd::f32x4` - - let _ = f32x4(0.0, 0.0, 0.0, 0.0) > f32x4(0.0, 0.0, 0.0, 0.0); - //~^ ERROR binary comparison operation `>` not supported for floating point SIMD vector `core::simd::f32x4` - -} diff --git a/src/test/compile-fail/simd-type.rs b/src/test/compile-fail/simd-type.rs index c47bc1747de3c..cde63aa0cd164 100644 --- a/src/test/compile-fail/simd-type.rs +++ b/src/test/compile-fail/simd-type.rs @@ -8,18 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(simd)] +#![feature(repr_simd)] -#[simd] -struct vec4(T, T, T, T); //~ ERROR SIMD vector cannot be generic - -#[simd] +#[repr(simd)] struct empty; //~ ERROR SIMD vector cannot be empty -#[simd] +#[repr(simd)] struct i64f64(i64, f64); //~ ERROR SIMD vector should be homogeneous -#[simd] +#[repr(simd)] struct int4(isize, isize, isize, isize); //~ ERROR SIMD vector element type should be machine type fn main() {} diff --git a/src/test/run-fail/overflowing-simd-lsh-1.rs b/src/test/run-fail/overflowing-simd-lsh-1.rs deleted file mode 100644 index a3bce00ee07cc..0000000000000 --- a/src/test/run-fail/overflowing-simd-lsh-1.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:thread '
' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::i32x4; - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn main() { - let _x = i32x4(1, 0, 0, 0) << id(i32x4(32, 0, 0, 0)); -} diff --git a/src/test/run-fail/overflowing-simd-lsh-2.rs b/src/test/run-fail/overflowing-simd-lsh-2.rs deleted file mode 100644 index e119bd03c8884..0000000000000 --- a/src/test/run-fail/overflowing-simd-lsh-2.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:thread '
' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::i32x4; - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn main() { - let _x = i32x4(1, 0, 0, 0) << id(i32x4(-1, 0, 0, 0)); -} diff --git a/src/test/run-fail/overflowing-simd-lsh-3.rs b/src/test/run-fail/overflowing-simd-lsh-3.rs deleted file mode 100644 index 4fb7fa958f041..0000000000000 --- a/src/test/run-fail/overflowing-simd-lsh-3.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:thread '
' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::u64x2; - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn main() { - let _x = u64x2(1, 0) << id(u64x2(64, 0)); -} diff --git a/src/test/run-fail/overflowing-simd-lsh-4.rs b/src/test/run-fail/overflowing-simd-lsh-4.rs deleted file mode 100644 index 2fc177ced9ddb..0000000000000 --- a/src/test/run-fail/overflowing-simd-lsh-4.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:thread '
' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -// This function is checking that our automatic truncation does not -// sidestep the overflow checking. - -#![feature(core_simd)] - -use std::simd::i8x16; - -fn eq_i8x16(i8x16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15): i8x16, - i8x16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15): i8x16) - -> bool -{ - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) - && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7) - && (x8 == y8) && (x9 == y9) && (x10 == y10) && (x11 == y11) - && (x12 == y12) && (x13 == y13) && (x14 == y14) && (x15 == y15) -} - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn main() { - // this signals overflow when checking is on - let x = i8x16(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) - << id(i8x16(17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); - - // ... but when checking is off, the fallback will truncate the - // input to its lower three bits (= 1). Note that this is *not* - // the behavior of the x86 processor for 8- and 16-bit types, - // but it is necessary to avoid undefined behavior from LLVM. - // - // We check that here, by ensuring the result has only been - // shifted by one place; if overflow checking is turned off, then - // this assertion will pass (and the compiletest driver will - // report that the test did not produce the error expected above). - assert!(eq_i8x16(x, i8x16(2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); -} diff --git a/src/test/run-fail/overflowing-simd-rsh-1.rs b/src/test/run-fail/overflowing-simd-rsh-1.rs deleted file mode 100644 index dffd627a0849f..0000000000000 --- a/src/test/run-fail/overflowing-simd-rsh-1.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:thread '
' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::i32x4; - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn main() { - let _x = i32x4(-1, 0, 0, 0) >> id(i32x4(32, 0, 0, 0)); -} diff --git a/src/test/run-fail/overflowing-simd-rsh-2.rs b/src/test/run-fail/overflowing-simd-rsh-2.rs deleted file mode 100644 index 2852e147f837d..0000000000000 --- a/src/test/run-fail/overflowing-simd-rsh-2.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:thread '
' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::i32x4; - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn main() { - let _x = i32x4(0, 0, 0, -1) >> id(i32x4(0, 0, 0, -1)); -} diff --git a/src/test/run-fail/overflowing-simd-rsh-3.rs b/src/test/run-fail/overflowing-simd-rsh-3.rs deleted file mode 100644 index 057eaa3f91aa0..0000000000000 --- a/src/test/run-fail/overflowing-simd-rsh-3.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:thread '
' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::i64x2; - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn main() { - let _x = i64x2(0, -1) >> id(i64x2(0, 64)); -} diff --git a/src/test/run-fail/overflowing-simd-rsh-4.rs b/src/test/run-fail/overflowing-simd-rsh-4.rs deleted file mode 100644 index a850fff691917..0000000000000 --- a/src/test/run-fail/overflowing-simd-rsh-4.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:thread '
' panicked at 'shift operation overflowed' -// compile-flags: -C debug-assertions - -// This function is checking that our (type-based) automatic -// truncation does not sidestep the overflow checking. - -#![feature(core_simd)] - -use std::simd::i8x16; - -fn eq_i8x16(i8x16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15): i8x16, - i8x16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15): i8x16) - -> bool -{ - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) - && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7) - && (x8 == y8) && (x9 == y9) && (x10 == y10) && (x11 == y11) - && (x12 == y12) && (x13 == y13) && (x14 == y14) && (x15 == y15) -} - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn main() { - // this signals overflow when checking is on - let x = i8x16(2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) - >> id(i8x16(17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); - - // ... but when checking is off, the fallback will truncate the - // input to its lower three bits (= 1). Note that this is *not* - // the behavior of the x86 processor for 8- and 16-bit types, - // but it is necessary to avoid undefined behavior from LLVM. - // - // We check that here, by ensuring the result is not zero; if - // overflow checking is turned off, then this assertion will pass - // (and the compiletest driver will report that the test did not - // produce the error expected above). - assert!(eq_i8x16(x, i8x16(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); -} diff --git a/src/test/run-make/simd-ffi/simd.rs b/src/test/run-make/simd-ffi/simd.rs index 5576e8823716d..c0c4b1e7f3f31 100644 --- a/src/test/run-make/simd-ffi/simd.rs +++ b/src/test/run-make/simd-ffi/simd.rs @@ -15,12 +15,12 @@ #![feature(no_core)] #![no_core] -#![feature(simd, simd_ffi, link_llvm_intrinsics, lang_items)] +#![feature(repr_simd, simd_ffi, link_llvm_intrinsics, lang_items)] #[repr(C)] #[derive(Copy)] -#[simd] +#[repr(simd)] pub struct f32x4(f32, f32, f32, f32); @@ -35,7 +35,7 @@ pub fn foo(x: f32x4) -> f32x4 { #[repr(C)] #[derive(Copy)] -#[simd] +#[repr(simd)] pub struct i32x4(i32, i32, i32, i32); diff --git a/src/test/run-pass/issue-17170.rs b/src/test/run-pass/issue-17170.rs index ef1345259278d..c786064ba01ae 100644 --- a/src/test/run-pass/issue-17170.rs +++ b/src/test/run-pass/issue-17170.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(simd)] +#![feature(repr_simd)] -#[simd] +#[repr(simd)] struct T(f64, f64, f64); static X: T = T(0.0, 0.0, 0.0); diff --git a/src/test/run-pass/issue-23037.rs b/src/test/run-pass/issue-23037.rs deleted file mode 100644 index a8abbda32bdfc..0000000000000 --- a/src/test/run-pass/issue-23037.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(core_simd)] - -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); -} diff --git a/src/test/run-pass/issue-24258.rs b/src/test/run-pass/issue-24258.rs deleted file mode 100644 index f56c3fefbe8f3..0000000000000 --- a/src/test/run-pass/issue-24258.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: -C debug-assertions - -#![feature(core_simd)] - -use std::simd::u32x4; - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn eq_u32x4(u32x4(x0, x1, x2, x3): u32x4, u32x4(y0, y1, y2, y3): u32x4) -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) -} - -fn main() { - assert!(eq_u32x4(u32x4(1, 1, 1, 1) << id(u32x4(1, 1, 1, 1)), u32x4(2, 2, 2, 2))); -} diff --git a/src/test/run-pass/simd-binop.rs b/src/test/run-pass/simd-binop.rs deleted file mode 100644 index 4f5119f6a84e9..0000000000000 --- a/src/test/run-pass/simd-binop.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -#![feature(core_simd)] - -use std::simd::{i32x4, f32x4, u32x4}; - -fn eq_u32x4(u32x4(x0, x1, x2, x3): u32x4, u32x4(y0, y1, y2, y3): u32x4) -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) -} - -fn eq_f32x4(f32x4(x0, x1, x2, x3): f32x4, f32x4(y0, y1, y2, y3): f32x4) -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) -} - -fn eq_i32x4(i32x4(x0, x1, x2, x3): i32x4, i32x4(y0, y1, y2, y3): i32x4) -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) -} - -pub fn main() { - // arithmetic operators - - assert!(eq_u32x4(u32x4(1, 2, 3, 4) + u32x4(4, 3, 2, 1), u32x4(5, 5, 5, 5))); - assert!(eq_u32x4(u32x4(4, 5, 6, 7) - u32x4(4, 3, 2, 1), u32x4(0, 2, 4, 6))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) * u32x4(4, 3, 2, 1), u32x4(4, 6, 6, 4))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) / u32x4(4, 3, 2, 1), u32x4(0, 0, 1, 4))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) & u32x4(4, 3, 2, 1), u32x4(0, 2, 2, 0))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) | u32x4(4, 3, 2, 1), u32x4(5, 3, 3, 5))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) ^ u32x4(4, 3, 2, 1), u32x4(5, 1, 1, 5))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) << u32x4(4, 3, 2, 1), u32x4(16, 16, 12, 8))); - assert!(eq_u32x4(u32x4(1, 2, 3, 4) >> u32x4(4, 3, 2, 1), u32x4(0, 0, 0, 2))); - - assert!(eq_i32x4(i32x4(1, 2, 3, 4) + i32x4(4, 3, 2, 1), i32x4(5, 5, 5, 5))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) - i32x4(4, 3, 2, 1), i32x4(-3, -1, 1, 3))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) * i32x4(4, 3, 2, 1), i32x4(4, 6, 6, 4))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) / i32x4(4, 3, 2, 1), i32x4(0, 0, 1, 4))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) & i32x4(4, 3, 2, 1), i32x4(0, 2, 2, 0))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) | i32x4(4, 3, 2, 1), i32x4(5, 3, 3, 5))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) ^ i32x4(4, 3, 2, 1), i32x4(5, 1, 1, 5))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) << i32x4(4, 3, 2, 1), i32x4(16, 16, 12, 8))); - assert!(eq_i32x4(i32x4(1, 2, 3, 4) >> i32x4(4, 3, 2, 1), i32x4(0, 0, 0, 2))); - - assert!(eq_f32x4(f32x4(1.0, 2.0, 3.0, 4.0) + f32x4(4.0, 3.0, 2.0, 1.0), - f32x4(5.0, 5.0, 5.0, 5.0))); - assert!(eq_f32x4(f32x4(1.0, 2.0, 3.0, 4.0) - f32x4(4.0, 3.0, 2.0, 1.0), - f32x4(-3.0, -1.0, 1.0, 3.0))); - assert!(eq_f32x4(f32x4(1.0, 2.0, 3.0, 4.0) * f32x4(4.0, 3.0, 2.0, 1.0), - f32x4(4.0, 6.0, 6.0, 4.0))); - assert!(eq_f32x4(f32x4(1.0, 2.0, 3.0, 4.0) / f32x4(4.0, 4.0, 2.0, 1.0), - f32x4(0.25, 0.5, 1.5, 4.0))); - - // comparison operators - - // check !0/-1 to ensure operators are using the correct signedness. - assert!(eq_u32x4(u32x4(1, 2, 3, !0) == u32x4(3, 2, 1, 0), u32x4(0, !0, 0, 0))); - assert!(eq_u32x4(u32x4(1, 2, 3, !0) != u32x4(3, 2, 1, 0), u32x4(!0, 0, !0, !0))); - assert!(eq_u32x4(u32x4(1, 2, 3, !0) < u32x4(3, 2, 1, 0), u32x4(!0, 0, 0, 0))); - assert!(eq_u32x4(u32x4(1, 2, 3, !0) <= u32x4(3, 2, 1, 0), u32x4(!0, !0, 0, 0))); - assert!(eq_u32x4(u32x4(1, 2, 3, !0) >= u32x4(3, 2, 1, 0), u32x4(0, !0, !0, !0))); - assert!(eq_u32x4(u32x4(1, 2, 3, !0) > u32x4(3, 2, 1, 0), u32x4(0, 0, !0, !0))); - - assert!(eq_i32x4(i32x4(1, 2, 3, -1) == i32x4(3, 2, 1, 0), i32x4(0, !0, 0, 0))); - assert!(eq_i32x4(i32x4(1, 2, 3, -1) != i32x4(3, 2, 1, 0), i32x4(!0, 0, !0, !0))); - assert!(eq_i32x4(i32x4(1, 2, 3, -1) < i32x4(3, 2, 1, 0), i32x4(!0, 0, 0, !0))); - assert!(eq_i32x4(i32x4(1, 2, 3, -1) <= i32x4(3, 2, 1, 0), i32x4(!0, !0, 0, !0))); - assert!(eq_i32x4(i32x4(1, 2, 3, -1) >= i32x4(3, 2, 1, 0), i32x4(0, !0, !0, 0))); - assert!(eq_i32x4(i32x4(1, 2, 3, -1) > i32x4(3, 2, 1, 0), i32x4(0, 0, !0, 0))); -} diff --git a/src/test/run-pass/simd-generics.rs b/src/test/run-pass/simd-generics.rs index 0e3d6b83a4be6..ef40a6ce96bd4 100644 --- a/src/test/run-pass/simd-generics.rs +++ b/src/test/run-pass/simd-generics.rs @@ -10,14 +10,18 @@ -#![feature(simd)] +#![feature(repr_simd, platform_intrinsics)] use std::ops; -#[simd] +#[repr(simd)] #[derive(Copy, Clone)] struct f32x4(f32, f32, f32, f32); +extern "platform-intrinsic" { + fn simd_add(x: T, y: T) -> T; +} + fn add>(lhs: T, rhs: T) -> T { lhs + rhs } @@ -26,7 +30,7 @@ impl ops::Add for f32x4 { type Output = f32x4; fn add(self, rhs: f32x4) -> f32x4 { - self + rhs + unsafe {simd_add(self, rhs)} } } diff --git a/src/test/run-pass/simd-shift-near-oflo.rs b/src/test/run-pass/simd-shift-near-oflo.rs deleted file mode 100644 index fee4637f07f21..0000000000000 --- a/src/test/run-pass/simd-shift-near-oflo.rs +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: -C debug-assertions - -// Check that we do *not* overflow on a number of edge cases. -// (compare with test/run-fail/overflowing-{lsh,rsh}*.rs) - -#![feature(core_simd)] - -use std::simd::{i8x16, i16x8, i32x4, i64x2, u8x16, u16x8, u32x4, u64x2}; - -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - -fn single_i8x16(x: i8) -> i8x16 { i8x16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x) } -fn single_u8x16(x: u8) -> u8x16 { u8x16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x) } -fn single_i16x8(x: i16) -> i16x8 { i16x8(0, 0, 0, 0, 0, 0, 0, x) } -fn single_u16x8(x: u16) -> u16x8 { u16x8(0, 0, 0, 0, 0, 0, 0, x) } -fn single_i32x4(x: i32) -> i32x4 { i32x4(0, 0, 0, x) } -fn single_u32x4(x: u32) -> u32x4 { u32x4(0, 0, 0, x) } -fn single_i64x2(x: i64) -> i64x2 { i64x2(0, x) } -fn single_u64x2(x: u64) -> u64x2 { u64x2(0, x) } - -fn eq_i8x16(i8x16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15): i8x16, - i8x16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15): i8x16) - -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) - && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7) - && (x8 == y8) && (x9 == y9) && (x10 == y10) && (x11 == y11) - && (x12 == y12) && (x13 == y13) && (x14 == y14) && (x15 == y15) -} -fn eq_u8x16(u8x16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15): u8x16, - u8x16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15): u8x16) - -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) - && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7) - && (x8 == y8) && (x9 == y9) && (x10 == y10) && (x11 == y11) - && (x12 == y12) && (x13 == y13) && (x14 == y14) && (x15 == y15) -} -fn eq_i16x8(i16x8(x0, x1, x2, x3, x4, x5, x6, x7): i16x8, - i16x8(y0, y1, y2, y3, y4, y5, y6, y7): i16x8) -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) - && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7) -} -fn eq_u16x8(u16x8(x0, x1, x2, x3, x4, x5, x6, x7): u16x8, - u16x8(y0, y1, y2, y3, y4, y5, y6, y7): u16x8) -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) - && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7) -} -fn eq_i32x4(i32x4(x0, x1, x2, x3): i32x4, i32x4(y0, y1, y2, y3): i32x4) -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) -} -fn eq_u32x4(u32x4(x0, x1, x2, x3): u32x4, u32x4(y0, y1, y2, y3): u32x4) -> bool { - (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3) -} -fn eq_i64x2(i64x2(x0, x1): i64x2, i64x2(y0, y1): i64x2) -> bool { - (x0 == y0) && (x1 == y1) -} -fn eq_u64x2(u64x2(x0, x1): u64x2, u64x2(y0, y1): u64x2) -> bool { - (x0 == y0) && (x1 == y1) -} - -fn main() { - test_left_shift(); - test_right_shift(); -} - -fn test_left_shift() { - // negative rhs can panic, but values in [0,N-1] are okay for iN - - macro_rules! tests { - ($single:ident, $eq:ident, $max_rhs:expr, $expect:expr) => { { - let x = $single(1) << id($single(0)); - assert!($eq(x, $single(1))); - let x = $single(1) << id($single($max_rhs)); - assert!($eq(x, $single($expect))); - // high-order bits on LHS are silently discarded without panic. - let x = $single(3) << id($single($max_rhs)); - assert!($eq(x, $single($expect))); - } } - } - - let x = single_i8x16(1) << id(single_i8x16(0)); - assert!(eq_i8x16(x, single_i8x16(1))); - let x = single_u8x16(1) << id(single_u8x16(0)); - assert!(eq_u8x16(x, single_u8x16(1))); - let x = single_i8x16(1) << id(single_i8x16(7)); - assert!(eq_i8x16(x, single_i8x16(std::i8::MIN))); - let x = single_u8x16(1) << id(single_u8x16(7)); - assert!(eq_u8x16(x, single_u8x16(0x80))); - // high-order bits on LHS are silently discarded without panic. - let x = single_i8x16(3) << id(single_i8x16(7)); - assert!(eq_i8x16(x, single_i8x16(std::i8::MIN))); - let x = single_u8x16(3) << id(single_u8x16(7)); - assert!(eq_u8x16(x, single_u8x16(0x80))); - - // above is (approximately) expanded from: - tests!(single_i8x16, eq_i8x16, 7, std::i8::MIN); - tests!(single_u8x16, eq_u8x16, 7, 0x80_u8); - - tests!(single_i16x8, eq_i16x8, 15, std::i16::MIN); - tests!(single_u16x8, eq_u16x8, 15, 0x8000_u16); - - tests!(single_i32x4, eq_i32x4, 31, std::i32::MIN); - tests!(single_u32x4, eq_u32x4, 31, 0x8000_0000_u32); - - tests!(single_i64x2, eq_i64x2, 63, std::i64::MIN); - tests!(single_u64x2, eq_u64x2, 63, 0x8000_0000_0000_0000_u64); -} - -fn test_right_shift() { - // negative rhs can panic, but values in [0,N-1] are okay for iN - - macro_rules! tests { - ($single_i:ident, $eq_i:ident, $single_u:ident, $eq_u:ident, - $max_rhs:expr, $signbit_i:expr, $highbit_i:expr, $highbit_u:expr) => { { - let x = $single_i(1) >> id($single_i(0)); - assert!($eq_i(x, $single_i(1))); - let x = $single_u(1) >> id($single_u(0)); - assert!($eq_u(x, $single_u(1))); - let x = $single_u($highbit_i) >> id($single_u($max_rhs-1)); - assert!($eq_u(x, $single_u(1))); - let x = $single_u($highbit_u) >> id($single_u($max_rhs)); - assert!($eq_u(x, $single_u(1))); - // sign-bit is carried by arithmetic right shift - let x = $single_i($signbit_i) >> id($single_i($max_rhs)); - assert!($eq_i(x, $single_i(-1))); - // low-order bits on LHS are silently discarded without panic. - let x = $single_u($highbit_i + 1) >> id($single_u($max_rhs-1)); - assert!($eq_u(x, $single_u(1))); - let x = $single_u($highbit_u + 1) >> id($single_u($max_rhs)); - assert!($eq_u(x, $single_u(1))); - let x = $single_i($signbit_i + 1) >> id($single_i($max_rhs)); - assert!($eq_i(x, $single_i(-1))); - } } - } - - tests!(single_i8x16, eq_i8x16, single_u8x16, eq_u8x16, - 7, std::i8::MIN, 0x40_u8, 0x80_u8); - tests!(single_i16x8, eq_i16x8, single_u16x8, eq_u16x8, - 15, std::i16::MIN, 0x4000_u16, 0x8000_u16); - tests!(single_i32x4, eq_i32x4, single_u32x4, eq_u32x4, - 31, std::i32::MIN, 0x4000_0000_u32, 0x8000_0000_u32); - tests!(single_i64x2, eq_i64x2, single_u64x2, eq_u64x2, - 63, std::i64::MIN, 0x4000_0000_0000_0000_u64, 0x8000_0000_0000_0000_u64); -} diff --git a/src/test/run-pass/simd-size-align.rs b/src/test/run-pass/simd-size-align.rs index 025b2a77375e8..b8d7cd8414176 100644 --- a/src/test/run-pass/simd-size-align.rs +++ b/src/test/run-pass/simd-size-align.rs @@ -9,7 +9,7 @@ // except according to those terms. -#![feature(simd)] +#![feature(repr_simd)] #![allow(non_camel_case_types)] use std::mem; @@ -46,26 +46,26 @@ fn main() { check::(); } -#[simd] struct u8x2(u8, u8); -#[simd] struct u8x3(u8, u8, u8); -#[simd] struct u8x4(u8, u8, u8, u8); -#[simd] struct u8x5(u8, u8, u8, u8, u8); -#[simd] struct u8x6(u8, u8, u8, u8, u8, u8); -#[simd] struct u8x7(u8, u8, u8, u8, u8, u8, u8); -#[simd] struct u8x8(u8, u8, u8, u8, u8, u8, u8, u8); +#[repr(simd)] struct u8x2(u8, u8); +#[repr(simd)] struct u8x3(u8, u8, u8); +#[repr(simd)] struct u8x4(u8, u8, u8, u8); +#[repr(simd)] struct u8x5(u8, u8, u8, u8, u8); +#[repr(simd)] struct u8x6(u8, u8, u8, u8, u8, u8); +#[repr(simd)] struct u8x7(u8, u8, u8, u8, u8, u8, u8); +#[repr(simd)] struct u8x8(u8, u8, u8, u8, u8, u8, u8, u8); -#[simd] struct i16x2(i16, i16); -#[simd] struct i16x3(i16, i16, i16); -#[simd] struct i16x4(i16, i16, i16, i16); -#[simd] struct i16x5(i16, i16, i16, i16, i16); -#[simd] struct i16x6(i16, i16, i16, i16, i16, i16); -#[simd] struct i16x7(i16, i16, i16, i16, i16, i16, i16); -#[simd] struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); +#[repr(simd)] struct i16x2(i16, i16); +#[repr(simd)] struct i16x3(i16, i16, i16); +#[repr(simd)] struct i16x4(i16, i16, i16, i16); +#[repr(simd)] struct i16x5(i16, i16, i16, i16, i16); +#[repr(simd)] struct i16x6(i16, i16, i16, i16, i16, i16); +#[repr(simd)] struct i16x7(i16, i16, i16, i16, i16, i16, i16); +#[repr(simd)] struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); -#[simd] struct f32x2(f32, f32); -#[simd] struct f32x3(f32, f32, f32); -#[simd] struct f32x4(f32, f32, f32, f32); -#[simd] struct f32x5(f32, f32, f32, f32, f32); -#[simd] struct f32x6(f32, f32, f32, f32, f32, f32); -#[simd] struct f32x7(f32, f32, f32, f32, f32, f32, f32); -#[simd] struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); +#[repr(simd)] struct f32x2(f32, f32); +#[repr(simd)] struct f32x3(f32, f32, f32); +#[repr(simd)] struct f32x4(f32, f32, f32, f32); +#[repr(simd)] struct f32x5(f32, f32, f32, f32, f32); +#[repr(simd)] struct f32x6(f32, f32, f32, f32, f32, f32); +#[repr(simd)] struct f32x7(f32, f32, f32, f32, f32, f32, f32); +#[repr(simd)] struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); diff --git a/src/test/run-pass/simd-type.rs b/src/test/run-pass/simd-type.rs index 540666f41ae2b..2883b80a25b9e 100644 --- a/src/test/run-pass/simd-type.rs +++ b/src/test/run-pass/simd-type.rs @@ -11,9 +11,9 @@ // pretty-expanded FIXME #23616 -#![feature(simd)] +#![feature(repr_simd)] -#[simd] +#[repr(simd)] struct RGBA { r: f32, g: f32, From 926b8351cf1d1489386bbf96355990ae01f6cb11 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 12 Aug 2015 21:11:50 -0700 Subject: [PATCH 32/40] Tweak intrinsic error handling. Better error messages, US spelling, more real checks. --- src/librustc_trans/trans/intrinsic.rs | 69 ++++++++++++++++++--------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index e076e376b0907..90a85e8736458 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -1359,21 +1359,24 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> if let Some(cmp_op) = comparison { assert_eq!(arg_tys.len(), 2); - // we need nominal equality here, not LLVM (structural) - // equality - require!(arg_tys[0] == arg_tys[1], - "SIMD comparison intrinsic monomorphised with different input types"); require!(arg_tys[0].is_simd(tcx), - "SIMD comparison intrinsic monomorphised for non-SIMD argument type"); + "SIMD comparison intrinsic monomorphized for non-SIMD argument type `{}`", + arg_tys[0]); require!(ret_ty.is_simd(tcx), - "SIMD comparison intrinsic monomorphised for non-SIMD return type"); + "SIMD comparison intrinsic monomorphized for non-SIMD return type `{}`", + ret_ty); let in_len = arg_tys[0].simd_size(tcx); let out_len = ret_ty.simd_size(tcx); require!(in_len == out_len, - "SIMD comparison intrinsic monomorphised for non-SIMD argument type"); + "SIMD cast intrinsic monomorphized with input type `{}` and \ + return type `{}` with different lengths: {} vs. {}", + arg_tys[0], + ret_ty, + in_len, + out_len); require!(llret_ty.element_type().kind() == llvm::Integer, - "SIMD comparison intrinsic monomorphised with non-integer return"); + "SIMD comparison intrinsic monomorphized with non-integer return"); return compare_simd_types(bcx, llargs[0], @@ -1391,18 +1394,20 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> "bad `simd_shuffle` instruction only caught in trans?") }; - require!(arg_tys[0] == arg_tys[1], - "SIMD shuffle intrinsic monomorphised with different input types"); + require!(arg_tys[0].is_simd(tcx), + "SIMD shuffle intrinsic monomorphized with non-SIMD input type `{}`", + arg_tys[0]); require!(ret_ty.is_simd(tcx), - "SIMD shuffle intrinsic monomorphised for non-SIMD return type"); + "SIMD shuffle intrinsic monomorphized for non-SIMD return type `{}`", + ret_ty); let in_len = arg_tys[0].simd_size(tcx); let out_len = ret_ty.simd_size(tcx); require!(out_len == n, - "SIMD shuffle intrinsic monomorphised with return type of length {} (expected {})", + "SIMD shuffle intrinsic monomorphized with return type of length {} (expected {})", out_len, n); require!(arg_tys[0].simd_type(tcx) == ret_ty.simd_type(tcx), - "SIMD shuffle intrinsic monomorphised with different \ + "SIMD shuffle intrinsic monomorphized with different \ input and return element types"); let total_len = in_len as u64 * 2; @@ -1448,27 +1453,37 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> if name == "simd_insert" { require!(arg_tys[0].is_simd(tcx), - "SIMD insert intrinsic monomorphised for non-SIMD input type"); + "SIMD insert intrinsic monomorphized for non-SIMD input type"); let elem_ty = arg_tys[0].simd_type(tcx); require!(arg_tys[2] == elem_ty, - "SIMD insert intrinsic monomorphised with inserted type not SIMD element type"); + "SIMD insert intrinsic monomorphized with inserted type not SIMD element type"); return InsertElement(bcx, llargs[0], llargs[2], llargs[1]) } if name == "simd_extract" { require!(arg_tys[0].is_simd(tcx), - "SIMD insert intrinsic monomorphised for non-SIMD input type"); + "SIMD insert intrinsic monomorphized for non-SIMD input type"); let elem_ty = arg_tys[0].simd_type(tcx); require!(ret_ty == elem_ty, - "SIMD insert intrinsic monomorphised with returned type not SIMD element type"); + "SIMD insert intrinsic monomorphized with returned type not SIMD element type"); return ExtractElement(bcx, llargs[0], llargs[1]) } if name == "simd_cast" { + require!(arg_tys[0].is_simd(tcx), + "SIMD cast intrinsic monomorphized with non-SIMD input type `{}`", + arg_tys[0]); + require!(ret_ty.is_simd(tcx), + "SIMD cast intrinsic monomorphized with non-SIMD return type `{}`", + ret_ty); require!(arg_tys[0].simd_size(tcx) == ret_ty.simd_size(tcx), - "SIMD cast intrinsic monomorphised with input and \ - return types of different lengths"); + "SIMD cast intrinsic monomorphized with input type `{}` and \ + return type `{}` with different lengths: {} vs. {}", + arg_tys[0], + ret_ty, + arg_tys[0].simd_size(tcx), + ret_ty.simd_size(tcx)); // casting cares about nominal type, not just structural type let in_ = arg_tys[0].simd_type(tcx); let out = ret_ty.simd_type(tcx); @@ -1590,12 +1605,19 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> } _ => {} } - require!(false, "SIMD cast intrinsic monomorphised with incompatible cast"); + require!(false, + "SIMD cast intrinsic monomorphized with incompatible cast \ + from `{}` (element `{}`)to `{}` (element `{}`)", + arg_tys[0], in_, + ret_ty, out); } macro_rules! arith { ($($name: ident: $($($p: ident),* => $call: expr),*;)*) => { $( if name == stringify!($name) { + require!(arg_tys[0].is_simd(tcx), + "`{}` intrinsic monomorphized with non-SIMD type `{}`", + name, arg_tys[0]); let in_ = arg_tys[0].simd_type(tcx); match in_.sty { $( @@ -1606,8 +1628,11 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> _ => {}, } require!(false, - "{} intrinsic monomorphised with invalid type", - name) + "`{}` intrinsic monomorphized with SIMD vector `{}` \ + with unsupported element type `{}`", + name, + arg_tys[0], + in_) })* } } From 84de8caa87b085772cbe41de0b39630ccca3afab Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 12 Aug 2015 21:12:36 -0700 Subject: [PATCH 33/40] Add tests for various intrinsic behaviours. --- .../simd-intrinsic-declaration-type.rs | 57 ++++++++ .../simd-intrinsic-generic-arithmetic.rs | 102 ++++++++++++++ .../simd-intrinsic-generic-cast.rs | 51 +++++++ .../simd-intrinsic-generic-comparison.rs | 75 ++++++++++ .../simd-intrinsic-generic-elements.rs | 88 ++++++++++++ .../simd-intrinsic-single-nominal-type.rs | 33 +++++ .../simd-type-generic-monomorphisation.rs | 21 +++ .../simd-intrinsic-generic-arithmetic.rs | 111 +++++++++++++++ .../run-pass/simd-intrinsic-generic-cast.rs | 128 +++++++++++++++++ .../simd-intrinsic-generic-comparison.rs | 113 +++++++++++++++ .../simd-intrinsic-generic-elements.rs | 132 ++++++++++++++++++ 11 files changed, 911 insertions(+) create mode 100644 src/test/compile-fail/simd-intrinsic-declaration-type.rs create mode 100644 src/test/compile-fail/simd-intrinsic-generic-arithmetic.rs create mode 100644 src/test/compile-fail/simd-intrinsic-generic-cast.rs create mode 100644 src/test/compile-fail/simd-intrinsic-generic-comparison.rs create mode 100644 src/test/compile-fail/simd-intrinsic-generic-elements.rs create mode 100644 src/test/compile-fail/simd-intrinsic-single-nominal-type.rs create mode 100644 src/test/compile-fail/simd-type-generic-monomorphisation.rs create mode 100644 src/test/run-pass/simd-intrinsic-generic-arithmetic.rs create mode 100755 src/test/run-pass/simd-intrinsic-generic-cast.rs create mode 100644 src/test/run-pass/simd-intrinsic-generic-comparison.rs create mode 100644 src/test/run-pass/simd-intrinsic-generic-elements.rs diff --git a/src/test/compile-fail/simd-intrinsic-declaration-type.rs b/src/test/compile-fail/simd-intrinsic-declaration-type.rs new file mode 100644 index 0000000000000..effa1ed04d8ec --- /dev/null +++ b/src/test/compile-fail/simd-intrinsic-declaration-type.rs @@ -0,0 +1,57 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); +#[repr(simd)] +struct u16x8(u16, u16, u16, u16, u16, u16, u16, u16); + +#[repr(simd)] +struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, + i8, i8, i8, i8, i8, i8, i8, i8); +#[repr(simd)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +struct f32x4(f32, f32, f32, f32); +#[repr(simd)] +struct i64x2(i64, i64); + +// signed vs. unsigned doesn't matter +mod i { + use i16x8; + extern "platform-intrinsic" { + fn x86_mm_adds_epi16(x: i16x8, y: i16x8) -> i16x8; + } +} +mod u { + use u16x8; + extern "platform-intrinsic" { + fn x86_mm_adds_epi16(x: u16x8, y: u16x8) -> u16x8; + } +} +// but lengths do +extern "platform-intrinsic" { + fn x86_mm_adds_epi16(x: i8x16, y: i32x4) -> i64x2; + //~^ ERROR intrinsic argument 1 has wrong type + //~^^ ERROR intrinsic argument 2 has wrong type + //~^^^ ERROR intrinsic return value has wrong type +} +// and so does int vs. float +extern "platform-intrinsic" { + fn x86_mm_max_ps(x: i32x4, y: i32x4) -> i32x4; + //~^ ERROR intrinsic argument 1 has wrong type + //~^^ ERROR intrinsic argument 2 has wrong type + //~^^^ ERROR intrinsic return value has wrong type +} + + +fn main() {} diff --git a/src/test/compile-fail/simd-intrinsic-generic-arithmetic.rs b/src/test/compile-fail/simd-intrinsic-generic-arithmetic.rs new file mode 100644 index 0000000000000..d4fbcb41e2a91 --- /dev/null +++ b/src/test/compile-fail/simd-intrinsic-generic-arithmetic.rs @@ -0,0 +1,102 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct i32x4(pub i32, pub i32, pub i32, pub i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_add(x: T, y: T) -> T; + fn simd_sub(x: T, y: T) -> T; + fn simd_mul(x: T, y: T) -> T; + fn simd_div(x: T, y: T) -> T; + fn simd_shl(x: T, y: T) -> T; + fn simd_shr(x: T, y: T) -> T; + fn simd_and(x: T, y: T) -> T; + fn simd_or(x: T, y: T) -> T; + fn simd_xor(x: T, y: T) -> T; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + let y = u32x4(0, 0, 0, 0); + let z = f32x4(0.0, 0.0, 0.0, 0.0); + + unsafe { + simd_add(x, x); + simd_add(y, y); + simd_add(z, z); + simd_sub(x, x); + simd_sub(y, y); + simd_sub(z, z); + simd_mul(x, x); + simd_mul(y, y); + simd_mul(z, z); + + simd_div(z, z); + + simd_shl(x, x); + simd_shl(y, y); + simd_shr(x, x); + simd_shr(y, y); + simd_and(x, x); + simd_and(y, y); + simd_or(x, x); + simd_or(y, y); + simd_xor(x, x); + simd_xor(y, y); + + + simd_add(0, 0); + //~^ ERROR `simd_add` intrinsic monomorphized with non-SIMD type + simd_sub(0, 0); + //~^ ERROR `simd_sub` intrinsic monomorphized with non-SIMD type + simd_mul(0, 0); + //~^ ERROR `simd_mul` intrinsic monomorphized with non-SIMD type + simd_div(0, 0); + //~^ ERROR `simd_div` intrinsic monomorphized with non-SIMD type + simd_shl(0, 0); + //~^ ERROR `simd_shl` intrinsic monomorphized with non-SIMD type + simd_shr(0, 0); + //~^ ERROR `simd_shr` intrinsic monomorphized with non-SIMD type + simd_and(0, 0); + //~^ ERROR `simd_and` intrinsic monomorphized with non-SIMD type + simd_or(0, 0); + //~^ ERROR `simd_or` intrinsic monomorphized with non-SIMD type + simd_xor(0, 0); + //~^ ERROR `simd_xor` intrinsic monomorphized with non-SIMD type + + + simd_div(x, x); +//~^ ERROR `simd_div` intrinsic monomorphized with SIMD vector `i32x4` with unsupported element type + simd_div(y, y); +//~^ ERROR `simd_div` intrinsic monomorphized with SIMD vector `u32x4` with unsupported element type + simd_shl(z, z); +//~^ ERROR `simd_shl` intrinsic monomorphized with SIMD vector `f32x4` with unsupported element type + simd_shr(z, z); +//~^ ERROR `simd_shr` intrinsic monomorphized with SIMD vector `f32x4` with unsupported element type + simd_and(z, z); +//~^ ERROR `simd_and` intrinsic monomorphized with SIMD vector `f32x4` with unsupported element type + simd_or(z, z); +//~^ ERROR `simd_or` intrinsic monomorphized with SIMD vector `f32x4` with unsupported element type + simd_xor(z, z); +//~^ ERROR `simd_xor` intrinsic monomorphized with SIMD vector `f32x4` with unsupported element type + } +} diff --git a/src/test/compile-fail/simd-intrinsic-generic-cast.rs b/src/test/compile-fail/simd-intrinsic-generic-cast.rs new file mode 100644 index 0000000000000..333ef756e1fa5 --- /dev/null +++ b/src/test/compile-fail/simd-intrinsic-generic-cast.rs @@ -0,0 +1,51 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x8(i32, i32, i32, i32, + i32, i32, i32, i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x4(f32, f32, f32, f32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x8(f32, f32, f32, f32, + f32, f32, f32, f32); + + +extern "platform-intrinsic" { + fn simd_cast(x: T) -> U; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + + unsafe { + simd_cast::(0); + //~^ ERROR SIMD cast intrinsic monomorphized with non-SIMD input type `i32` + simd_cast::(0); + //~^ ERROR SIMD cast intrinsic monomorphized with non-SIMD input type `i32` + simd_cast::(x); + //~^ ERROR SIMD cast intrinsic monomorphized with non-SIMD return type `i32` + simd_cast::<_, i32x8>(x); +//~^ ERROR monomorphized with input type `i32x4` and return type `i32x8` with different lengths + } +} diff --git a/src/test/compile-fail/simd-intrinsic-generic-comparison.rs b/src/test/compile-fail/simd-intrinsic-generic-comparison.rs new file mode 100644 index 0000000000000..37827fbb6fbbb --- /dev/null +++ b/src/test/compile-fail/simd-intrinsic-generic-comparison.rs @@ -0,0 +1,75 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i16x8(i16, i16, i16, i16, + i16, i16, i16, i16); + +extern "platform-intrinsic" { + fn simd_eq(x: T, y: T) -> U; + fn simd_ne(x: T, y: T) -> U; + fn simd_lt(x: T, y: T) -> U; + fn simd_le(x: T, y: T) -> U; + fn simd_gt(x: T, y: T) -> U; + fn simd_ge(x: T, y: T) -> U; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + + unsafe { + simd_eq::(0, 0); + //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD argument type + simd_ne::(0, 0); + //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD argument type + simd_lt::(0, 0); + //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD argument type + simd_le::(0, 0); + //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD argument type + simd_gt::(0, 0); + //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD argument type + simd_ge::(0, 0); + //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD argument type + + simd_eq::<_, i32>(x, x); + //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD return type + simd_ne::<_, i32>(x, x); + //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD return type + simd_lt::<_, i32>(x, x); + //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD return type + simd_le::<_, i32>(x, x); + //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD return type + simd_gt::<_, i32>(x, x); + //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD return type + simd_ge::<_, i32>(x, x); + //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD return type + + simd_eq::<_, i16x8>(x, x); +//~^ ERROR monomorphized with input type `i32x4` and return type `i16x8` with different lengths + simd_ne::<_, i16x8>(x, x); +//~^ ERROR monomorphized with input type `i32x4` and return type `i16x8` with different lengths + simd_lt::<_, i16x8>(x, x); +//~^ ERROR monomorphized with input type `i32x4` and return type `i16x8` with different lengths + simd_le::<_, i16x8>(x, x); +//~^ ERROR monomorphized with input type `i32x4` and return type `i16x8` with different lengths + simd_gt::<_, i16x8>(x, x); +//~^ ERROR monomorphized with input type `i32x4` and return type `i16x8` with different lengths + simd_ge::<_, i16x8>(x, x); +//~^ ERROR monomorphized with input type `i32x4` and return type `i16x8` with different lengths + } +} diff --git a/src/test/compile-fail/simd-intrinsic-generic-elements.rs b/src/test/compile-fail/simd-intrinsic-generic-elements.rs new file mode 100644 index 0000000000000..ebe442c1a2e4d --- /dev/null +++ b/src/test/compile-fail/simd-intrinsic-generic-elements.rs @@ -0,0 +1,88 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x3(i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x8(i32, i32, i32, i32, + i32, i32, i32, i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x2(f32, f32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x3(f32, f32, f32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x4(f32, f32, f32, f32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x8(f32, f32, f32, f32, + f32, f32, f32, f32); + +extern "platform-intrinsic" { + fn simd_insert(x: T, idx: u32, y: E) -> T; + fn simd_extract(x: T, idx: u32) -> E; + + fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; + fn simd_shuffle3(x: T, y: T, idx: [u32; 3]) -> U; + fn simd_shuffle4(x: T, y: T, idx: [u32; 4]) -> U; + fn simd_shuffle8(x: T, y: T, idx: [u32; 8]) -> U; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + + unsafe { + simd_insert(0, 0, 0); + //~^ ERROR SIMD insert intrinsic monomorphized for non-SIMD input type + simd_insert(x, 0, 1.0); + //~^ ERROR SIMD insert intrinsic monomorphized with inserted type not SIMD element type + simd_extract::<_, f32>(x, 0); + //~^ ERROR SIMD insert intrinsic monomorphized with returned type not SIMD element type + + simd_shuffle2::(0, 0, [0; 2]); + //~^ ERROR SIMD shuffle intrinsic monomorphized with non-SIMD input type + simd_shuffle3::(0, 0, [0; 3]); + //~^ ERROR SIMD shuffle intrinsic monomorphized with non-SIMD input type + simd_shuffle4::(0, 0, [0; 4]); + //~^ ERROR SIMD shuffle intrinsic monomorphized with non-SIMD input type + simd_shuffle8::(0, 0, [0; 8]); + //~^ ERROR SIMD shuffle intrinsic monomorphized with non-SIMD input type + + simd_shuffle2::<_, f32x2>(x, x, [0; 2]); + //~^ ERROR SIMD shuffle intrinsic monomorphized with different input and return element + simd_shuffle3::<_, f32x3>(x, x, [0; 3]); + //~^ ERROR SIMD shuffle intrinsic monomorphized with different input and return element + simd_shuffle4::<_, f32x4>(x, x, [0; 4]); + //~^ ERROR SIMD shuffle intrinsic monomorphized with different input and return element + simd_shuffle8::<_, f32x8>(x, x, [0; 8]); + //~^ ERROR SIMD shuffle intrinsic monomorphized with different input and return element + } +} diff --git a/src/test/compile-fail/simd-intrinsic-single-nominal-type.rs b/src/test/compile-fail/simd-intrinsic-single-nominal-type.rs new file mode 100644 index 0000000000000..0d0bf240f720a --- /dev/null +++ b/src/test/compile-fail/simd-intrinsic-single-nominal-type.rs @@ -0,0 +1,33 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +struct A(i16, i16, i16, i16, i16, i16, i16, i16); +#[repr(simd)] +struct B(i16, i16, i16, i16, i16, i16, i16, i16); + +// each intrinsic definition has to use the same nominal type for any +// vector structure throughout that declaration (i.e. every instance +// of i16x8 in each `fn ...;` needs to be either A or B) + +extern "platform-intrinsic" { + fn x86_mm_adds_epi16(x: A, y: A) -> B; + //~^ ERROR intrinsic return value has wrong type: found `B`, expected `A` + fn x86_mm_subs_epi16(x: A, y: B) -> A; + //~^ ERROR intrinsic argument 2 has wrong type: found `B`, expected `A` + + // ok: + fn x86_mm_max_epi16(x: B, y: B) -> B; + fn x86_mm_min_epi16(x: A, y: A) -> A; +} + +fn main() {} diff --git a/src/test/compile-fail/simd-type-generic-monomorphisation.rs b/src/test/compile-fail/simd-type-generic-monomorphisation.rs new file mode 100644 index 0000000000000..336855eb5e18b --- /dev/null +++ b/src/test/compile-fail/simd-type-generic-monomorphisation.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd, platform_intrinsics)] + +// error-pattern:monomorphising SIMD type `Simd2` with a non-machine element type `X` + +struct X(Vec); +#[repr(simd)] +struct Simd2(T, T); + +fn main() { + let _ = Simd2(X(vec![]), X(vec![])); +} diff --git a/src/test/run-pass/simd-intrinsic-generic-arithmetic.rs b/src/test/run-pass/simd-intrinsic-generic-arithmetic.rs new file mode 100644 index 0000000000000..5d4ecbb5f8172 --- /dev/null +++ b/src/test/run-pass/simd-intrinsic-generic-arithmetic.rs @@ -0,0 +1,111 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +struct i32x4(pub i32, pub i32, pub i32, pub i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +macro_rules! all_eq { + ($a: expr, $b: expr) => {{ + let a = $a; + let b = $b; + assert!(a.0 == b.0 && a.1 == b.1 && a.2 == b.2 && a.3 == b.3); + }} +} + +extern "platform-intrinsic" { + fn simd_add(x: T, y: T) -> T; + fn simd_sub(x: T, y: T) -> T; + fn simd_mul(x: T, y: T) -> T; + fn simd_div(x: T, y: T) -> T; + fn simd_shl(x: T, y: T) -> T; + fn simd_shr(x: T, y: T) -> T; + fn simd_and(x: T, y: T) -> T; + fn simd_or(x: T, y: T) -> T; + fn simd_xor(x: T, y: T) -> T; +} + +fn main() { + let x1 = i32x4(1, 2, 3, 4); + let y1 = u32x4(1, 2, 3, 4); + let z1 = f32x4(1.0, 2.0, 3.0, 4.0); + let x2 = i32x4(2, 3, 4, 5); + let y2 = u32x4(2, 3, 4, 5); + let z2 = f32x4(2.0, 3.0, 4.0, 5.0); + + unsafe { + all_eq!(simd_add(x1, x2), i32x4(3, 5, 7, 9)); + all_eq!(simd_add(x2, x1), i32x4(3, 5, 7, 9)); + all_eq!(simd_add(y1, y2), u32x4(3, 5, 7, 9)); + all_eq!(simd_add(y2, y1), u32x4(3, 5, 7, 9)); + all_eq!(simd_add(z1, z2), f32x4(3.0, 5.0, 7.0, 9.0)); + all_eq!(simd_add(z2, z1), f32x4(3.0, 5.0, 7.0, 9.0)); + + all_eq!(simd_mul(x1, x2), i32x4(2, 6, 12, 20)); + all_eq!(simd_mul(x2, x1), i32x4(2, 6, 12, 20)); + all_eq!(simd_mul(y1, y2), u32x4(2, 6, 12, 20)); + all_eq!(simd_mul(y2, y1), u32x4(2, 6, 12, 20)); + all_eq!(simd_mul(z1, z2), f32x4(2.0, 6.0, 12.0, 20.0)); + all_eq!(simd_mul(z2, z1), f32x4(2.0, 6.0, 12.0, 20.0)); + + all_eq!(simd_sub(x2, x1), i32x4(1, 1, 1, 1)); + all_eq!(simd_sub(x1, x2), i32x4(-1, -1, -1, -1)); + all_eq!(simd_sub(y2, y1), u32x4(1, 1, 1, 1)); + all_eq!(simd_sub(y1, y2), u32x4(!0, !0, !0, !0)); + all_eq!(simd_sub(z2, z1), f32x4(1.0, 1.0, 1.0, 1.0)); + all_eq!(simd_sub(z1, z2), f32x4(-1.0, -1.0, -1.0, -1.0)); + + all_eq!(simd_div(z1, z2), f32x4(1.0/2.0, 2.0/3.0, 3.0/4.0, 4.0/5.0)); + all_eq!(simd_div(z2, z1), f32x4(2.0/1.0, 3.0/2.0, 4.0/3.0, 5.0/4.0)); + + all_eq!(simd_shl(x1, x2), i32x4(1 << 2, 2 << 3, 3 << 4, 4 << 5)); + all_eq!(simd_shl(x2, x1), i32x4(2 << 1, 3 << 2, 4 << 3, 5 << 4)); + all_eq!(simd_shl(y1, y2), u32x4(1 << 2, 2 << 3, 3 << 4, 4 << 5)); + all_eq!(simd_shl(y2, y1), u32x4(2 << 1, 3 << 2, 4 << 3, 5 << 4)); + + // test right-shift by assuming left-shift is correct + all_eq!(simd_shr(simd_shl(x1, x2), x2), x1); + all_eq!(simd_shr(simd_shl(x2, x1), x1), x2); + all_eq!(simd_shr(simd_shl(y1, y2), y2), y1); + all_eq!(simd_shr(simd_shl(y2, y1), y1), y2); + + // ensure we get logical vs. arithmetic shifts correct + let (a, b, c, d) = (-12, -123, -1234, -12345); + all_eq!(simd_shr(i32x4(a, b, c, d), x1), i32x4(a >> 1, b >> 2, c >> 3, d >> 4)); + all_eq!(simd_shr(u32x4(a as u32, b as u32, c as u32, d as u32), y1), + u32x4((a as u32) >> 1, (b as u32) >> 2, (c as u32) >> 3, (d as u32) >> 4)); + + all_eq!(simd_and(x1, x2), i32x4(0, 2, 0, 4)); + all_eq!(simd_and(x2, x1), i32x4(0, 2, 0, 4)); + all_eq!(simd_and(y1, y2), u32x4(0, 2, 0, 4)); + all_eq!(simd_and(y2, y1), u32x4(0, 2, 0, 4)); + + all_eq!(simd_or(x1, x2), i32x4(3, 3, 7, 5)); + all_eq!(simd_or(x2, x1), i32x4(3, 3, 7, 5)); + all_eq!(simd_or(y1, y2), u32x4(3, 3, 7, 5)); + all_eq!(simd_or(y2, y1), u32x4(3, 3, 7, 5)); + + all_eq!(simd_xor(x1, x2), i32x4(3, 1, 7, 1)); + all_eq!(simd_xor(x2, x1), i32x4(3, 1, 7, 1)); + all_eq!(simd_xor(y1, y2), u32x4(3, 1, 7, 1)); + all_eq!(simd_xor(y2, y1), u32x4(3, 1, 7, 1)); + + } +} diff --git a/src/test/run-pass/simd-intrinsic-generic-cast.rs b/src/test/run-pass/simd-intrinsic-generic-cast.rs new file mode 100755 index 0000000000000..a20dd3ef72a54 --- /dev/null +++ b/src/test/run-pass/simd-intrinsic-generic-cast.rs @@ -0,0 +1,128 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd, platform_intrinsics, concat_idents, + type_macros, test)] +#![allow(non_camel_case_types)] + +extern crate test; + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct i8x4(i8, i8, i8, i8); + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct u32x4(u32, u32, u32, u32); +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct u8x4(u8, u8, u8, u8); + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct f32x4(f32, f32, f32, f32); + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct f64x4(f64, f64, f64, f64); + + +extern "platform-intrinsic" { + fn simd_cast(x: T) -> U; +} + +const A: i32 = -1234567; +const B: i32 = 12345678; +const C: i32 = -123456789; +const D: i32 = 1234567890; + +trait Foo { + fn is_float() -> bool { false } + fn in_range(x: i32) -> bool; +} +impl Foo for i32 { + fn in_range(_: i32) -> bool { true } +} +impl Foo for i8 { + fn in_range(x: i32) -> bool { -128 <= x && x < 128 } +} +impl Foo for u32 { + fn in_range(x: i32) -> bool { 0 <= x } +} +impl Foo for u8 { + fn in_range(x: i32) -> bool { 0 <= x && x < 128 } +} +impl Foo for f32 { + fn is_float() -> bool { true } + fn in_range(_: i32) -> bool { true } +} +impl Foo for f64 { + fn is_float() -> bool { true } + fn in_range(_: i32) -> bool { true } +} + +fn main() { + macro_rules! test { + ($from: ident, $to: ident) => {{ + // force the casts to actually happen, or else LLVM/rustc + // may fold them and get slightly different results. + let (a, b, c, d) = test::black_box((A as $from, B as $from, C as $from, D as $from)); + // the SIMD vectors are all FOOx4, so we can concat_idents + // so we don't have to pass in the extra args to the macro + let mut from = simd_cast(concat_idents!($from, x4)(a, b, c, d)); + let mut to = concat_idents!($to, x4)(a as $to, + b as $to, + c as $to, + d as $to); + // assist type inference, it needs to know what `from` is + // for the `if` statements. + to == from; + + // there are platform differences for some out of range + // casts, so we just normalize such things: it's OK for + // "invalid" calculations to result in nonsense answers. + // (E.g. negative float to unsigned integer goes through a + // library routine on the default i686 platforms, and the + // implementation of that routine differs on e.g. Linux + // vs. OSX, resulting in different answers.) + if $from::is_float() { + if !$to::in_range(A) { from.0 = 0 as $to; to.0 = 0 as $to; } + if !$to::in_range(B) { from.1 = 0 as $to; to.1 = 0 as $to; } + if !$to::in_range(C) { from.2 = 0 as $to; to.2 = 0 as $to; } + if !$to::in_range(D) { from.3 = 0 as $to; to.3 = 0 as $to; } + } + + assert!(to == from, + "{} -> {} ({:?} != {:?})", stringify!($from), stringify!($to), + from, to); + }} + } + macro_rules! tests { + (: $($to: ident),*) => { () }; + // repeating the list twice is easier than writing a cartesian + // product macro + ($from: ident $(, $from_: ident)*: $($to: ident),*) => { + fn $from() { unsafe { $( test!($from, $to); )* } } + tests!($($from_),*: $($to),*) + }; + ($($types: ident),*) => {{ + tests!($($types),* : $($types),*); + $($types();)* + }} + } + + // test various combinations, including truncation, + // signed/unsigned extension, and floating point casts. + tests!(i32, i8, u32, u8, f32); + tests!(i32, u32, f32, f64) +} diff --git a/src/test/run-pass/simd-intrinsic-generic-comparison.rs b/src/test/run-pass/simd-intrinsic-generic-comparison.rs new file mode 100644 index 0000000000000..5802fb30bd680 --- /dev/null +++ b/src/test/run-pass/simd-intrinsic-generic-comparison.rs @@ -0,0 +1,113 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd, platform_intrinsics, concat_idents)] +#![allow(non_camel_case_types)] + +use std::f32::NAN; + +#[repr(simd)] +#[derive(Copy, Clone)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +struct u32x4(pub u32, pub u32, pub u32, pub u32); +#[repr(simd)] +#[derive(Copy, Clone)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_eq(x: T, y: T) -> U; + fn simd_ne(x: T, y: T) -> U; + fn simd_lt(x: T, y: T) -> U; + fn simd_le(x: T, y: T) -> U; + fn simd_gt(x: T, y: T) -> U; + fn simd_ge(x: T, y: T) -> U; +} + +macro_rules! cmp { + ($method: ident($lhs: expr, $rhs: expr)) => {{ + let lhs = $lhs; + let rhs = $rhs; + let e: u32x4 = concat_idents!(simd_, $method)($lhs, $rhs); + // assume the scalar version is correct/the behaviour we want. + assert!((e.0 != 0) == lhs.0 .$method(&rhs.0)); + assert!((e.1 != 0) == lhs.1 .$method(&rhs.1)); + assert!((e.2 != 0) == lhs.2 .$method(&rhs.2)); + assert!((e.3 != 0) == lhs.3 .$method(&rhs.3)); + }} +} +macro_rules! tests { + ($($lhs: ident, $rhs: ident;)*) => {{ + $( + (|| { + cmp!(eq($lhs, $rhs)); + cmp!(ne($lhs, $rhs)); + + // test both directions + cmp!(lt($lhs, $rhs)); + cmp!(lt($rhs, $lhs)); + + cmp!(le($lhs, $rhs)); + cmp!(le($rhs, $lhs)); + + cmp!(gt($lhs, $rhs)); + cmp!(gt($rhs, $lhs)); + + cmp!(ge($lhs, $rhs)); + cmp!(ge($rhs, $lhs)); + })(); + )* + }} +} +fn main() { + // 13 vs. -100 tests that we get signed vs. unsigned comparisons + // correct (i32: 13 > -100, u32: 13 < -100). let i1 = i32x4(10, -11, 12, 13); + let i1 = i32x4(10, -11, 12, 13); + let i2 = i32x4(5, -5, 20, -100); + let i3 = i32x4(10, -11, 20, -100); + + let u1 = u32x4(10, !11+1, 12, 13); + let u2 = u32x4(5, !5+1, 20, !100+1); + let u3 = u32x4(10, !11+1, 20, !100+1); + + let f1 = f32x4(10.0, -11.0, 12.0, 13.0); + let f2 = f32x4(5.0, -5.0, 20.0, -100.0); + let f3 = f32x4(10.0, -11.0, 20.0, -100.0); + + unsafe { + tests! { + i1, i1; + u1, u1; + f1, f1; + + i1, i2; + u1, u2; + f1, f2; + + i1, i3; + u1, u3; + f1, f3; + } + } + + // NAN comparisons are special: + // -11 (*) 13 + // -5 -100 (*) + let f4 = f32x4(NAN, f1.1, NAN, f2.3); + + unsafe { + tests! { + f1, f4; + f2, f4; + f4, f4; + } + } +} diff --git a/src/test/run-pass/simd-intrinsic-generic-elements.rs b/src/test/run-pass/simd-intrinsic-generic-elements.rs new file mode 100644 index 0000000000000..f0444c2717056 --- /dev/null +++ b/src/test/run-pass/simd-intrinsic-generic-elements.rs @@ -0,0 +1,132 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x3(i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x8(i32, i32, i32, i32, + i32, i32, i32, i32); + +extern "platform-intrinsic" { + fn simd_insert(x: T, idx: u32, y: E) -> T; + fn simd_extract(x: T, idx: u32) -> E; + + fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; + fn simd_shuffle3(x: T, y: T, idx: [u32; 3]) -> U; + fn simd_shuffle4(x: T, y: T, idx: [u32; 4]) -> U; + fn simd_shuffle8(x: T, y: T, idx: [u32; 8]) -> U; +} + +macro_rules! all_eq { + ($a: expr, $b: expr) => {{ + let a = $a; + let b = $b; + // type inference works better with the concrete type on the + // left, but humans work better with the expected on the + // right. + assert!(b == a, + "{:?} != {:?}", a, b); + }} +} + +fn main() { + let x2 = i32x2(20, 21); + let x3 = i32x3(30, 31, 32); + let x4 = i32x4(40, 41, 42, 43); + let x8 = i32x8(80, 81, 82, 83, 84, 85, 86, 87); + unsafe { + all_eq!(simd_insert(x2, 0, 100), i32x2(100, 21)); + all_eq!(simd_insert(x2, 1, 100), i32x2(20, 100)); + + all_eq!(simd_insert(x3, 0, 100), i32x3(100, 31, 32)); + all_eq!(simd_insert(x3, 1, 100), i32x3(30, 100, 32)); + all_eq!(simd_insert(x3, 2, 100), i32x3(30, 31, 100)); + + all_eq!(simd_insert(x4, 0, 100), i32x4(100, 41, 42, 43)); + all_eq!(simd_insert(x4, 1, 100), i32x4(40, 100, 42, 43)); + all_eq!(simd_insert(x4, 2, 100), i32x4(40, 41, 100, 43)); + all_eq!(simd_insert(x4, 3, 100), i32x4(40, 41, 42, 100)); + + all_eq!(simd_insert(x8, 0, 100), i32x8(100, 81, 82, 83, 84, 85, 86, 87)); + all_eq!(simd_insert(x8, 1, 100), i32x8(80, 100, 82, 83, 84, 85, 86, 87)); + all_eq!(simd_insert(x8, 2, 100), i32x8(80, 81, 100, 83, 84, 85, 86, 87)); + all_eq!(simd_insert(x8, 3, 100), i32x8(80, 81, 82, 100, 84, 85, 86, 87)); + all_eq!(simd_insert(x8, 4, 100), i32x8(80, 81, 82, 83, 100, 85, 86, 87)); + all_eq!(simd_insert(x8, 5, 100), i32x8(80, 81, 82, 83, 84, 100, 86, 87)); + all_eq!(simd_insert(x8, 6, 100), i32x8(80, 81, 82, 83, 84, 85, 100, 87)); + all_eq!(simd_insert(x8, 7, 100), i32x8(80, 81, 82, 83, 84, 85, 86, 100)); + + all_eq!(simd_extract(x2, 0), 20); + all_eq!(simd_extract(x2, 1), 21); + + all_eq!(simd_extract(x3, 0), 30); + all_eq!(simd_extract(x3, 1), 31); + all_eq!(simd_extract(x3, 2), 32); + + all_eq!(simd_extract(x4, 0), 40); + all_eq!(simd_extract(x4, 1), 41); + all_eq!(simd_extract(x4, 2), 42); + all_eq!(simd_extract(x4, 3), 43); + + all_eq!(simd_extract(x8, 0), 80); + all_eq!(simd_extract(x8, 1), 81); + all_eq!(simd_extract(x8, 2), 82); + all_eq!(simd_extract(x8, 3), 83); + all_eq!(simd_extract(x8, 4), 84); + all_eq!(simd_extract(x8, 5), 85); + all_eq!(simd_extract(x8, 6), 86); + all_eq!(simd_extract(x8, 7), 87); + } + + let y2 = i32x2(120, 121); + let y3 = i32x3(130, 131, 132); + let y4 = i32x4(140, 141, 142, 143); + let y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187); + unsafe { + all_eq!(simd_shuffle2(x2, y2, [3, 0]), i32x2(121, 20)); + all_eq!(simd_shuffle3(x2, y2, [3, 0, 1]), i32x3(121, 20, 21)); + all_eq!(simd_shuffle4(x2, y2, [3, 0, 1, 2]), i32x4(121, 20, 21, 120)); + all_eq!(simd_shuffle8(x2, y2, [3, 0, 1, 2, 1, 2, 3, 0]), + i32x8(121, 20, 21, 120, 21, 120, 121, 20)); + + all_eq!(simd_shuffle2(x3, y3, [4, 2]), i32x2(131, 32)); + all_eq!(simd_shuffle3(x3, y3, [4, 2, 3]), i32x3(131, 32, 130)); + all_eq!(simd_shuffle4(x3, y3, [4, 2, 3, 0]), i32x4(131, 32, 130, 30)); + all_eq!(simd_shuffle8(x3, y3, [4, 2, 3, 0, 1, 5, 5, 1]), + i32x8(131, 32, 130, 30, 31, 132, 132, 31)); + + all_eq!(simd_shuffle2(x4, y4, [7, 2]), i32x2(143, 42)); + all_eq!(simd_shuffle3(x4, y4, [7, 2, 5]), i32x3(143, 42, 141)); + all_eq!(simd_shuffle4(x4, y4, [7, 2, 5, 0]), i32x4(143, 42, 141, 40)); + all_eq!(simd_shuffle8(x4, y4, [7, 2, 5, 0, 3, 6, 4, 1]), + i32x8(143, 42, 141, 40, 43, 142, 140, 41)); + + all_eq!(simd_shuffle2(x8, y8, [11, 5]), i32x2(183, 85)); + all_eq!(simd_shuffle3(x8, y8, [11, 5, 15]), i32x3(183, 85, 187)); + all_eq!(simd_shuffle4(x8, y8, [11, 5, 15, 0]), i32x4(183, 85, 187, 80)); + all_eq!(simd_shuffle8(x8, y8, [11, 5, 15, 0, 3, 8, 12, 1]), + i32x8(183, 85, 187, 80, 83, 180, 184, 81)); + } + +} From 4b242497d3a3b3fc4e56cf80053dfbecf1b1d308 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 13 Aug 2015 16:00:44 -0700 Subject: [PATCH 34/40] Code style tweaks. --- src/librustc_trans/trans/intrinsic.rs | 71 +++++++++++++-------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 90a85e8736458..18ea4387bf22f 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -918,37 +918,36 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } (_, _) => { - match Intrinsic::find(tcx, &name) { + let intr = match Intrinsic::find(tcx, &name) { + Some(intr) => intr, None => ccx.sess().span_bug(foreign_item.span, "unknown intrinsic"), - Some(intr) => { - 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) + }; + fn ty_to_type(ccx: &CrateContext, t: &intrinsics::Type) -> Type { + use intrinsics::Type::*; + match *t { + Integer(x) => Type::ix(ccx, x as u64), + Float(x) => { + match x { + 32 => Type::f32(ccx), + 64 => Type::f64(ccx), + _ => unreachable!() } } + Pointer(_) => unimplemented!(), + Vector(ref t, length) => Type::vector(&ty_to_type(ccx, t), + length as u64) + } + } - let inputs = intr.inputs.iter().map(|t| ty_to_type(ccx, t)).collect::>(); - let outputs = ty_to_type(ccx, &intr.output); - match intr.definition { - intrinsics::IntrinsicDef::Named(name) => { - let f = declare::declare_cfn(ccx, - name, - Type::func(&inputs, &outputs), - tcx.mk_nil()); - Call(bcx, f, &llargs, None, call_debug_location) - } - } + let inputs = intr.inputs.iter().map(|t| ty_to_type(ccx, t)).collect::>(); + let outputs = ty_to_type(ccx, &intr.output); + match intr.definition { + intrinsics::IntrinsicDef::Named(name) => { + let f = declare::declare_cfn(ccx, + name, + Type::func(&inputs, &outputs), + tcx.mk_nil()); + Call(bcx, f, &llargs, None, call_debug_location) } } } @@ -1330,6 +1329,15 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> call_debug_location: DebugLoc, call_info: NodeIdAndSpan) -> ValueRef { + macro_rules! require { + ($cond: expr, $($fmt: tt)*) => { + if !$cond { + bcx.sess().span_err(call_info.span, &format!($($fmt)*)); + return C_null(llret_ty) + } + } + } + let tcx = bcx.tcx(); let arg_tys = match callee_ty.sty { ty::TyBareFn(_, ref f) => { @@ -1348,15 +1356,6 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> _ => None }; - macro_rules! require { - ($cond: expr, $($fmt: tt)*) => { - if !$cond { - bcx.sess().span_err(call_info.span, &format!($($fmt)*)); - return C_null(llret_ty) - } - } - } - if let Some(cmp_op) = comparison { assert_eq!(arg_tys.len(), 2); require!(arg_tys[0].is_simd(tcx), From 62ba85b7aaf4ac1dbbf8b89605ff24d40f93969f Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 13 Aug 2015 21:34:20 -0700 Subject: [PATCH 35/40] Rebase cleanup: is_simd lost its parameter. --- src/librustc_trans/trans/intrinsic.rs | 18 +++++++++--------- src/librustc_typeck/check/intrinsic.rs | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 18ea4387bf22f..dbfd76d3082c5 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -1358,10 +1358,10 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> if let Some(cmp_op) = comparison { assert_eq!(arg_tys.len(), 2); - require!(arg_tys[0].is_simd(tcx), + require!(arg_tys[0].is_simd(), "SIMD comparison intrinsic monomorphized for non-SIMD argument type `{}`", arg_tys[0]); - require!(ret_ty.is_simd(tcx), + require!(ret_ty.is_simd(), "SIMD comparison intrinsic monomorphized for non-SIMD return type `{}`", ret_ty); @@ -1393,10 +1393,10 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> "bad `simd_shuffle` instruction only caught in trans?") }; - require!(arg_tys[0].is_simd(tcx), + require!(arg_tys[0].is_simd(), "SIMD shuffle intrinsic monomorphized with non-SIMD input type `{}`", arg_tys[0]); - require!(ret_ty.is_simd(tcx), + require!(ret_ty.is_simd(), "SIMD shuffle intrinsic monomorphized for non-SIMD return type `{}`", ret_ty); @@ -1451,7 +1451,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> } if name == "simd_insert" { - require!(arg_tys[0].is_simd(tcx), + require!(arg_tys[0].is_simd(), "SIMD insert intrinsic monomorphized for non-SIMD input type"); let elem_ty = arg_tys[0].simd_type(tcx); @@ -1460,7 +1460,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> return InsertElement(bcx, llargs[0], llargs[2], llargs[1]) } if name == "simd_extract" { - require!(arg_tys[0].is_simd(tcx), + require!(arg_tys[0].is_simd(), "SIMD insert intrinsic monomorphized for non-SIMD input type"); let elem_ty = arg_tys[0].simd_type(tcx); @@ -1470,10 +1470,10 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> } if name == "simd_cast" { - require!(arg_tys[0].is_simd(tcx), + require!(arg_tys[0].is_simd(), "SIMD cast intrinsic monomorphized with non-SIMD input type `{}`", arg_tys[0]); - require!(ret_ty.is_simd(tcx), + require!(ret_ty.is_simd(), "SIMD cast intrinsic monomorphized with non-SIMD return type `{}`", ret_ty); require!(arg_tys[0].simd_size(tcx) == ret_ty.simd_size(tcx), @@ -1614,7 +1614,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> ($($name: ident: $($($p: ident),* => $call: expr),*;)*) => { $( if name == stringify!($name) { - require!(arg_tys[0].is_simd(tcx), + require!(arg_tys[0].is_simd(), "`{}` intrinsic monomorphized with non-SIMD type `{}`", name, arg_tys[0]); let in_ = arg_tys[0].simd_type(tcx); diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 8b5fbcd02f552..fe59054dd0840 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -481,7 +481,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>( }, Pointer(_) => unimplemented!(), Vector(ref inner_expected, len) => { - if !t.is_simd(tcx) { + if !t.is_simd() { simple_error(&format!("non-simd type `{}`", t), "simd type"); return; From d792925b4d838ca6d15c2d86b0e3dc85f6a393fe Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Fri, 14 Aug 2015 12:06:10 -0700 Subject: [PATCH 36/40] Shim some of the old std::simd functionality. Overload the operators using the traits so that things mostly keep working during the deprecation period. --- src/libcore/lib.rs | 2 +- src/libcore/simd.rs | 68 ++++++++++++++++++++----- src/test/bench/shootout-spectralnorm.rs | 2 +- 3 files changed, 56 insertions(+), 16 deletions(-) diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index d21cfbcdfce9b..e226e9fa1549b 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -79,7 +79,7 @@ #![feature(reflect)] #![feature(rustc_attrs)] #![cfg_attr(stage0, feature(simd))] -#![cfg_attr(not(stage0), feature(repr_simd))] +#![cfg_attr(not(stage0), feature(repr_simd, platform_intrinsics))] #![feature(staged_api)] #![feature(unboxed_closures)] diff --git a/src/libcore/simd.rs b/src/libcore/simd.rs index d58d0c50a8982..fb39b3accc344 100644 --- a/src/libcore/simd.rs +++ b/src/libcore/simd.rs @@ -10,25 +10,12 @@ //! SIMD vectors. //! -//! These types can be used for accessing basic SIMD operations. Each of them -//! implements the standard arithmetic operator traits (Add, Sub, Mul, Div, -//! Rem, Shl, Shr) through compiler magic, rather than explicitly. Currently +//! These types can be used for accessing basic SIMD operations. Currently //! comparison operators are not implemented. To use SSE3+, you must enable //! the features, like `-C target-feature=sse3,sse4.1,sse4.2`, or a more //! specific `target-cpu`. No other SIMD intrinsics or high-level wrappers are //! provided beyond this module. //! -//! ```rust -//! #![feature(core_simd)] -//! -//! fn main() { -//! use std::simd::f32x4; -//! let a = f32x4(40.0, 41.0, 42.0, 43.0); -//! let b = f32x4(1.0, 1.1, 3.4, 9.8); -//! println!("{:?}", a + b); -//! } -//! ``` -//! //! # Stability Note //! //! These are all experimental. The interface may change entirely, without @@ -44,6 +31,30 @@ #![allow(missing_docs)] #![allow(deprecated)] +use ops::{Add, Sub, Mul, Div, Shl, Shr, BitAnd, BitOr, BitXor}; + +// FIXME(stage0): the contents of macro can be inlined. +// ABIs are verified as valid as soon as they are parsed, i.e. before +// `cfg` stripping. The `platform-intrinsic` ABI is new, so stage0 +// doesn't know about it, but it still errors out when it hits it +// (despite this being in a `cfg(not(stage0))` module). +macro_rules! argh { + () => { + extern "platform-intrinsic" { + fn simd_add(x: T, y: T) -> T; + fn simd_sub(x: T, y: T) -> T; + fn simd_mul(x: T, y: T) -> T; + fn simd_div(x: T, y: T) -> T; + fn simd_shl(x: T, y: T) -> T; + fn simd_shr(x: T, y: T) -> T; + fn simd_and(x: T, y: T) -> T; + fn simd_or(x: T, y: T) -> T; + fn simd_xor(x: T, y: T) -> T; + } + } +} +argh!(); + #[repr(simd)] #[derive(Copy, Clone, Debug)] #[repr(C)] @@ -101,3 +112,32 @@ pub struct f32x4(pub f32, pub f32, pub f32, pub f32); #[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/test/bench/shootout-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs index b359147702282..a6c77eaf7c630 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -91,7 +91,7 @@ fn mult(v: &[f64], out: &mut [f64], start: usize, a: F) for (j, chunk) in v.chunks(2).enumerate().map(|(j, s)| (2 * j, s)) { let top = f64x2(chunk[0], chunk[1]); let bot = f64x2(a(i, j), a(i, j + 1)); - sum += top / bot; + sum = sum + top / bot; } let f64x2(a, b) = sum; *slot = a + b; From 891c91438da66e967314f74f7ad5c06ddf56d917 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Fri, 14 Aug 2015 13:45:42 -0700 Subject: [PATCH 37/40] simd_shuffleNNN returns its type parameter directly. I.e. the signature now must be fn simd_shuffleNNN(x: T, y: T, idx: [u32; NNN]) -> U; (modulo names.) --- src/librustc_typeck/check/intrinsic.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index fe59054dd0840..636f17db38c36 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -13,7 +13,6 @@ use astconv::AstConv; use intrinsics; -use middle::infer; use middle::subst; use middle::ty::FnSig; use middle::ty::{self, Ty}; @@ -29,7 +28,6 @@ use syntax::codemap::Span; use syntax::parse::token; fn equate_intrinsic_type<'a, 'tcx>(tcx: &ty::ctxt<'tcx>, it: &ast::ForeignItem, - maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>, n_tps: usize, abi: abi::Abi, inputs: Vec>, @@ -52,7 +50,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: &ty::ctxt<'tcx>, it: &ast::ForeignItem, i_n_tps, n_tps); } else { require_same_types(tcx, - maybe_infcx, + None, false, it.span, i_ty.ty, @@ -349,7 +347,6 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { equate_intrinsic_type( tcx, it, - None, n_tps, abi::RustIntrinsic, inputs, @@ -369,7 +366,6 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, 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 mut infer_ctxt = None; let (n_tps, inputs, output) = match &*name { "simd_eq" | "simd_ne" | "simd_lt" | "simd_le" | "simd_gt" | "simd_ge" => { @@ -388,11 +384,7 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, Ok(n) => { let params = vec![param(0), param(0), tcx.mk_ty(ty::TyArray(tcx.types.u32, n))]; - - let ictxt = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); - let ret = ictxt.next_ty_var(); - infer_ctxt = Some(ictxt); - (2, params, ret) + (2, params, param(1)) } Err(_) => { span_err!(tcx.sess, it.span, E0439, @@ -438,7 +430,6 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, equate_intrinsic_type( tcx, it, - infer_ctxt.as_ref(), n_tps, abi::PlatformIntrinsic, inputs, From 502f9acbe9a41c64c92a3eba8186e8b44963fc76 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Fri, 14 Aug 2015 15:20:22 -0700 Subject: [PATCH 38/40] Revamp SIMD intrinsic trans error handling. Factor out common pieces, follow `expected ..., found ...` convention everywhere. --- src/librustc_trans/trans/intrinsic.rs | 153 ++++++++---------- .../simd-intrinsic-generic-arithmetic.rs | 32 ++-- .../simd-intrinsic-generic-cast.rs | 8 +- .../simd-intrinsic-generic-comparison.rs | 36 ++--- .../simd-intrinsic-generic-elements.rs | 31 ++-- 5 files changed, 129 insertions(+), 131 deletions(-) diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index dbfd76d3082c5..185a5cb47466e 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -1329,14 +1329,33 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> 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 { - bcx.sess().span_err(call_info.span, &format!($($fmt)*)); + 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 { @@ -1346,6 +1365,12 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> _ => 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), @@ -1357,30 +1382,23 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> }; if let Some(cmp_op) = comparison { - assert_eq!(arg_tys.len(), 2); - require!(arg_tys[0].is_simd(), - "SIMD comparison intrinsic monomorphized for non-SIMD argument type `{}`", - arg_tys[0]); - require!(ret_ty.is_simd(), - "SIMD comparison intrinsic monomorphized for non-SIMD return type `{}`", - ret_ty); - - let in_len = arg_tys[0].simd_size(tcx); + require_simd!(ret_ty, "return"); + let out_len = ret_ty.simd_size(tcx); require!(in_len == out_len, - "SIMD cast intrinsic monomorphized with input type `{}` and \ - return type `{}` with different lengths: {} vs. {}", - arg_tys[0], - ret_ty, - 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, - "SIMD comparison intrinsic monomorphized with non-integer return"); + "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], - arg_tys[0].simd_type(tcx), + in_elem, llret_ty, cmp_op, call_debug_location) @@ -1390,24 +1408,20 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> 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?") + "bad `simd_shuffle` instruction only caught in trans?") }; - require!(arg_tys[0].is_simd(), - "SIMD shuffle intrinsic monomorphized with non-SIMD input type `{}`", - arg_tys[0]); - require!(ret_ty.is_simd(), - "SIMD shuffle intrinsic monomorphized for non-SIMD return type `{}`", - ret_ty); + require_simd!(ret_ty, "return"); - let in_len = arg_tys[0].simd_size(tcx); let out_len = ret_ty.simd_size(tcx); require!(out_len == n, - "SIMD shuffle intrinsic monomorphized with return type of length {} (expected {})", - out_len, n); - require!(arg_tys[0].simd_type(tcx) == ret_ty.simd_type(tcx), - "SIMD shuffle intrinsic monomorphized with different \ - input and return element types"); + "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; @@ -1425,17 +1439,12 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> let c = const_to_opt_uint(val); match c { None => { - bcx.sess().span_err(call_info.span, - &format!("SIMD shuffle intrinsic argument #{} \ - is not a constant", - arg_idx)); + emit_error!("shuffle index #{} is not a constant", arg_idx); None } Some(idx) if idx >= total_len => { - bcx.sess().span_err(call_info.span, - &format!("SIMD shuffle intrinsic argument #{} \ - is out of bounds (limit {})", - arg_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)), @@ -1451,45 +1460,32 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> } if name == "simd_insert" { - require!(arg_tys[0].is_simd(), - "SIMD insert intrinsic monomorphized for non-SIMD input type"); - - let elem_ty = arg_tys[0].simd_type(tcx); - require!(arg_tys[2] == elem_ty, - "SIMD insert intrinsic monomorphized with inserted type not SIMD element type"); + 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!(arg_tys[0].is_simd(), - "SIMD insert intrinsic monomorphized for non-SIMD input type"); - - let elem_ty = arg_tys[0].simd_type(tcx); - require!(ret_ty == elem_ty, - "SIMD insert intrinsic monomorphized with returned type not SIMD element type"); + 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!(arg_tys[0].is_simd(), - "SIMD cast intrinsic monomorphized with non-SIMD input type `{}`", - arg_tys[0]); - require!(ret_ty.is_simd(), - "SIMD cast intrinsic monomorphized with non-SIMD return type `{}`", - ret_ty); - require!(arg_tys[0].simd_size(tcx) == ret_ty.simd_size(tcx), - "SIMD cast intrinsic monomorphized with input type `{}` and \ - return type `{}` with different lengths: {} vs. {}", - arg_tys[0], - ret_ty, - arg_tys[0].simd_size(tcx), - ret_ty.simd_size(tcx)); + 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 in_ = arg_tys[0].simd_type(tcx); - let out = ret_ty.simd_type(tcx); + let out_elem = ret_ty.simd_type(tcx); - if in_ == out { return llargs[0]; } + if in_elem == out_elem { return llargs[0]; } - match (&in_.sty, &out.sty) { + match (&in_elem.sty, &out_elem.sty) { (&ty::TyInt(lhs), &ty::TyInt(rhs)) => { match (lhs, rhs) { (ast::TyI8, ast::TyI8) | @@ -1605,20 +1601,15 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> _ => {} } require!(false, - "SIMD cast intrinsic monomorphized with incompatible cast \ - from `{}` (element `{}`)to `{}` (element `{}`)", - arg_tys[0], in_, - ret_ty, out); + "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) { - require!(arg_tys[0].is_simd(), - "`{}` intrinsic monomorphized with non-SIMD type `{}`", - name, arg_tys[0]); - let in_ = arg_tys[0].simd_type(tcx); - match in_.sty { + match in_elem.sty { $( $(ty::$p(_))|* => { return $call(bcx, llargs[0], llargs[1], call_debug_location) @@ -1627,11 +1618,9 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> _ => {}, } require!(false, - "`{}` intrinsic monomorphized with SIMD vector `{}` \ - with unsupported element type `{}`", - name, - arg_tys[0], - in_) + "unsupported operation on `{}` with element `{}`", + in_ty, + in_elem) })* } } diff --git a/src/test/compile-fail/simd-intrinsic-generic-arithmetic.rs b/src/test/compile-fail/simd-intrinsic-generic-arithmetic.rs index d4fbcb41e2a91..35c368f4cbedb 100644 --- a/src/test/compile-fail/simd-intrinsic-generic-arithmetic.rs +++ b/src/test/compile-fail/simd-intrinsic-generic-arithmetic.rs @@ -65,38 +65,38 @@ fn main() { simd_add(0, 0); - //~^ ERROR `simd_add` intrinsic monomorphized with non-SIMD type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_sub(0, 0); - //~^ ERROR `simd_sub` intrinsic monomorphized with non-SIMD type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_mul(0, 0); - //~^ ERROR `simd_mul` intrinsic monomorphized with non-SIMD type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_div(0, 0); - //~^ ERROR `simd_div` intrinsic monomorphized with non-SIMD type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_shl(0, 0); - //~^ ERROR `simd_shl` intrinsic monomorphized with non-SIMD type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_shr(0, 0); - //~^ ERROR `simd_shr` intrinsic monomorphized with non-SIMD type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_and(0, 0); - //~^ ERROR `simd_and` intrinsic monomorphized with non-SIMD type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_or(0, 0); - //~^ ERROR `simd_or` intrinsic monomorphized with non-SIMD type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_xor(0, 0); - //~^ ERROR `simd_xor` intrinsic monomorphized with non-SIMD type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_div(x, x); -//~^ ERROR `simd_div` intrinsic monomorphized with SIMD vector `i32x4` with unsupported element type +//~^ ERROR unsupported operation on `i32x4` with element `i32` simd_div(y, y); -//~^ ERROR `simd_div` intrinsic monomorphized with SIMD vector `u32x4` with unsupported element type +//~^ ERROR unsupported operation on `u32x4` with element `u32` simd_shl(z, z); -//~^ ERROR `simd_shl` intrinsic monomorphized with SIMD vector `f32x4` with unsupported element type +//~^ ERROR unsupported operation on `f32x4` with element `f32` simd_shr(z, z); -//~^ ERROR `simd_shr` intrinsic monomorphized with SIMD vector `f32x4` with unsupported element type +//~^ ERROR unsupported operation on `f32x4` with element `f32` simd_and(z, z); -//~^ ERROR `simd_and` intrinsic monomorphized with SIMD vector `f32x4` with unsupported element type +//~^ ERROR unsupported operation on `f32x4` with element `f32` simd_or(z, z); -//~^ ERROR `simd_or` intrinsic monomorphized with SIMD vector `f32x4` with unsupported element type +//~^ ERROR unsupported operation on `f32x4` with element `f32` simd_xor(z, z); -//~^ ERROR `simd_xor` intrinsic monomorphized with SIMD vector `f32x4` with unsupported element type +//~^ 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 index 333ef756e1fa5..4999b790b130a 100644 --- a/src/test/compile-fail/simd-intrinsic-generic-cast.rs +++ b/src/test/compile-fail/simd-intrinsic-generic-cast.rs @@ -40,12 +40,12 @@ fn main() { unsafe { simd_cast::(0); - //~^ ERROR SIMD cast intrinsic monomorphized with non-SIMD input type `i32` + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_cast::(0); - //~^ ERROR SIMD cast intrinsic monomorphized with non-SIMD input type `i32` + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_cast::(x); - //~^ ERROR SIMD cast intrinsic monomorphized with non-SIMD return type `i32` + //~^ ERROR expected SIMD return type, found non-SIMD `i32` simd_cast::<_, i32x8>(x); -//~^ ERROR monomorphized with input type `i32x4` and return type `i32x8` with different lengths +//~^ 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 index 37827fbb6fbbb..617b03a87117b 100644 --- a/src/test/compile-fail/simd-intrinsic-generic-comparison.rs +++ b/src/test/compile-fail/simd-intrinsic-generic-comparison.rs @@ -34,42 +34,42 @@ fn main() { unsafe { simd_eq::(0, 0); - //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD argument type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_ne::(0, 0); - //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD argument type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_lt::(0, 0); - //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD argument type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_le::(0, 0); - //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD argument type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_gt::(0, 0); - //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD argument type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_ge::(0, 0); - //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD argument type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_eq::<_, i32>(x, x); - //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD return type + //~^ ERROR expected SIMD return type, found non-SIMD `i32` simd_ne::<_, i32>(x, x); - //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD return type + //~^ ERROR expected SIMD return type, found non-SIMD `i32` simd_lt::<_, i32>(x, x); - //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD return type + //~^ ERROR expected SIMD return type, found non-SIMD `i32` simd_le::<_, i32>(x, x); - //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD return type + //~^ ERROR expected SIMD return type, found non-SIMD `i32` simd_gt::<_, i32>(x, x); - //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD return type + //~^ ERROR expected SIMD return type, found non-SIMD `i32` simd_ge::<_, i32>(x, x); - //~^ ERROR SIMD comparison intrinsic monomorphized for non-SIMD return type + //~^ ERROR expected SIMD return type, found non-SIMD `i32` simd_eq::<_, i16x8>(x, x); -//~^ ERROR monomorphized with input type `i32x4` and return type `i16x8` with different lengths +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 simd_ne::<_, i16x8>(x, x); -//~^ ERROR monomorphized with input type `i32x4` and return type `i16x8` with different lengths +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 simd_lt::<_, i16x8>(x, x); -//~^ ERROR monomorphized with input type `i32x4` and return type `i16x8` with different lengths +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 simd_le::<_, i16x8>(x, x); -//~^ ERROR monomorphized with input type `i32x4` and return type `i16x8` with different lengths +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 simd_gt::<_, i16x8>(x, x); -//~^ ERROR monomorphized with input type `i32x4` and return type `i16x8` with different lengths +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 simd_ge::<_, i16x8>(x, x); -//~^ ERROR monomorphized with input type `i32x4` and return type `i16x8` with different lengths +//~^ 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 index ebe442c1a2e4d..b0198c411d567 100644 --- a/src/test/compile-fail/simd-intrinsic-generic-elements.rs +++ b/src/test/compile-fail/simd-intrinsic-generic-elements.rs @@ -61,28 +61,37 @@ fn main() { unsafe { simd_insert(0, 0, 0); - //~^ ERROR SIMD insert intrinsic monomorphized for non-SIMD input type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_insert(x, 0, 1.0); - //~^ ERROR SIMD insert intrinsic monomorphized with inserted type not SIMD element type + //~^ ERROR expected inserted type `i32` (element of input `i32x4`), found `f64` simd_extract::<_, f32>(x, 0); - //~^ ERROR SIMD insert intrinsic monomorphized with returned type not SIMD element type + //~^ ERROR expected return type `i32` (element of input `i32x4`), found `f32` simd_shuffle2::(0, 0, [0; 2]); - //~^ ERROR SIMD shuffle intrinsic monomorphized with non-SIMD input type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_shuffle3::(0, 0, [0; 3]); - //~^ ERROR SIMD shuffle intrinsic monomorphized with non-SIMD input type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_shuffle4::(0, 0, [0; 4]); - //~^ ERROR SIMD shuffle intrinsic monomorphized with non-SIMD input type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_shuffle8::(0, 0, [0; 8]); - //~^ ERROR SIMD shuffle intrinsic monomorphized with non-SIMD input type + //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_shuffle2::<_, f32x2>(x, x, [0; 2]); - //~^ ERROR SIMD shuffle intrinsic monomorphized with different input and return element +//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` simd_shuffle3::<_, f32x3>(x, x, [0; 3]); - //~^ ERROR SIMD shuffle intrinsic monomorphized with different input and return element +//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x3` with element type `f32` simd_shuffle4::<_, f32x4>(x, x, [0; 4]); - //~^ ERROR SIMD shuffle intrinsic monomorphized with different input and return element +//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` simd_shuffle8::<_, f32x8>(x, x, [0; 8]); - //~^ ERROR SIMD shuffle intrinsic monomorphized with different input and return element +//~^ 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 } } From b067e4464bc8f519485476935d7d6b2bc860e569 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Fri, 14 Aug 2015 15:46:51 -0700 Subject: [PATCH 39/40] Clean up simd_cast translation. --- src/librustc_trans/trans/intrinsic.rs | 151 ++++++++------------------ src/libsyntax/ast.rs | 24 ++++ 2 files changed, 69 insertions(+), 106 deletions(-) diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 185a5cb47466e..ded748e9894a0 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -43,6 +43,8 @@ use syntax::ast; use syntax::ptr::P; use syntax::parse::token; +use std::cmp::Ordering; + pub fn get_simple_intrinsic(ccx: &CrateContext, item: &ast::ForeignItem) -> Option { let name = match &*item.ident.name.as_str() { "sqrtf32" => "llvm.sqrt.f32", @@ -1485,120 +1487,57 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> if in_elem == out_elem { return llargs[0]; } - match (&in_elem.sty, &out_elem.sty) { - (&ty::TyInt(lhs), &ty::TyInt(rhs)) => { - match (lhs, rhs) { - (ast::TyI8, ast::TyI8) | - (ast::TyI16, ast::TyI16) | - (ast::TyI32, ast::TyI32) | - (ast::TyI64, ast::TyI64) => return llargs[0], - - (ast::TyI8, ast::TyI16) | - (ast::TyI8, ast::TyI32) | - (ast::TyI8, ast::TyI64) | - (ast::TyI16, ast::TyI32) | - (ast::TyI16, ast::TyI64) | - (ast::TyI32, ast::TyI64) => return SExt(bcx, llargs[0], llret_ty), - - (ast::TyI16, ast::TyI8) | - (ast::TyI32, ast::TyI8) | - (ast::TyI32, ast::TyI16) | - (ast::TyI64, ast::TyI8) | - (ast::TyI64, ast::TyI16) | - (ast::TyI64, ast::TyI32) => return Trunc(bcx, llargs[0], llret_ty), - _ => {} + 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) + } } } - (&ty::TyUint(lhs), &ty::TyUint(rhs)) => { - match (lhs, rhs) { - (ast::TyU8, ast::TyU8) | - (ast::TyU16, ast::TyU16) | - (ast::TyU32, ast::TyU32) | - (ast::TyU64, ast::TyU64) => return llargs[0], - - (ast::TyU8, ast::TyU16) | - (ast::TyU8, ast::TyU32) | - (ast::TyU8, ast::TyU64) | - (ast::TyU16, ast::TyU32) | - (ast::TyU16, ast::TyU64) | - (ast::TyU32, ast::TyU64) => return ZExt(bcx, llargs[0], llret_ty), - - (ast::TyU16, ast::TyU8) | - (ast::TyU32, ast::TyU8) | - (ast::TyU32, ast::TyU16) | - (ast::TyU64, ast::TyU8) | - (ast::TyU64, ast::TyU16) | - (ast::TyU64, ast::TyU32) => return Trunc(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) } } - (&ty::TyInt(lhs), &ty::TyUint(rhs)) => { - match (lhs, rhs) { - (ast::TyI8, ast::TyU8) | - (ast::TyI16, ast::TyU16) | - (ast::TyI32, ast::TyU32) | - (ast::TyI64, ast::TyU64) => return llargs[0], - - (ast::TyI8, ast::TyU16) | - (ast::TyI8, ast::TyU32) | - (ast::TyI8, ast::TyU64) | - (ast::TyI16, ast::TyU32) | - (ast::TyI16, ast::TyU64) | - (ast::TyI32, ast::TyU64) => return SExt(bcx, llargs[0], llret_ty), - - (ast::TyI16, ast::TyU8) | - (ast::TyI32, ast::TyU8) | - (ast::TyI32, ast::TyU16) | - (ast::TyI64, ast::TyU8) | - (ast::TyI64, ast::TyU16) | - (ast::TyI64, ast::TyU32) => return Trunc(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) } } - (&ty::TyUint(lhs), &ty::TyInt(rhs)) => { - match (lhs, rhs) { - (ast::TyU8, ast::TyI8) | - (ast::TyU16, ast::TyI16) | - (ast::TyU32, ast::TyI32) | - (ast::TyU64, ast::TyI64) => return llargs[0], - - (ast::TyU8, ast::TyI16) | - (ast::TyU8, ast::TyI32) | - (ast::TyU8, ast::TyI64) | - (ast::TyU16, ast::TyI32) | - (ast::TyU16, ast::TyI64) | - (ast::TyU32, ast::TyI64) => return ZExt(bcx, llargs[0], llret_ty), - - (ast::TyU16, ast::TyI8) | - (ast::TyU32, ast::TyI8) | - (ast::TyU32, ast::TyI16) | - (ast::TyU64, ast::TyI8) | - (ast::TyU64, ast::TyI16) | - (ast::TyU64, ast::TyI32) => return Trunc(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) } } - - (&ty::TyInt(_), &ty::TyFloat(_)) => { - return SIToFP(bcx, llargs[0], llret_ty) - } - (&ty::TyUint(_), &ty::TyFloat(_)) => { - return UIToFP(bcx, llargs[0], llret_ty) - } - - (&ty::TyFloat(_), &ty::TyInt(_)) => { - return FPToSI(bcx, llargs[0], llret_ty) - } - (&ty::TyFloat(_), &ty::TyUint(_)) => { - return FPToUI(bcx, llargs[0], llret_ty) - } - (&ty::TyFloat(ast::TyF32), &ty::TyFloat(ast::TyF64)) => { - return FPExt(bcx, llargs[0], llret_ty) - } - (&ty::TyFloat(ast::TyF64), &ty::TyFloat(ast::TyF32)) => { - return FPTrunc(bcx, llargs[0], llret_ty) - } - _ => {} + _ => {/* Unsupported. Fallthrough. */} } require!(false, "unsupported cast from `{}` with element `{}` to `{}` with element `{}`", diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 0bcd97cfe873f..2d72c8fe2a48c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1339,6 +1339,15 @@ impl IntTy { TyI16 | TyI32 | TyI64 => 3, } } + pub fn bit_width(&self) -> Option { + Some(match *self { + TyIs => return None, + TyI8 => 8, + TyI16 => 16, + TyI32 => 32, + TyI64 => 64, + }) + } } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] @@ -1357,6 +1366,15 @@ impl UintTy { TyU16 | TyU32 | TyU64 => 3, } } + pub fn bit_width(&self) -> Option { + Some(match *self { + TyUs => return None, + TyU8 => 8, + TyU16 => 16, + TyU32 => 32, + TyU64 => 64, + }) + } } impl fmt::Debug for UintTy { @@ -1395,6 +1413,12 @@ impl FloatTy { TyF32 | TyF64 => 3, // add F128 handling here } } + pub fn bit_width(&self) -> usize { + match *self { + TyF32 => 32, + TyF64 => 64, + } + } } // Bind a type to an associated type: `A=Foo`. From 02e97342c136d2d13411ebd0a687100d8be248e0 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Fri, 14 Aug 2015 21:25:52 -0700 Subject: [PATCH 40/40] Add AArch64 vrecpeq_... intrinsic (necessary for minimal API). --- src/librustc_platform_intrinsics/aarch64.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_platform_intrinsics/aarch64.rs b/src/librustc_platform_intrinsics/aarch64.rs index 2bdb9ce4327bc..e7b11e45fd6c7 100644 --- a/src/librustc_platform_intrinsics/aarch64.rs +++ b/src/librustc_platform_intrinsics/aarch64.rs @@ -38,6 +38,8 @@ pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option { "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),