Skip to content

Commit

Permalink
Auto merge of #49664 - alexcrichton:stable-simd, r=BurntSushi
Browse files Browse the repository at this point in the history
Stabilize x86/x86_64 SIMD

This commit stabilizes the SIMD in Rust for the x86/x86_64 platforms. Notably
this commit is stabilizing:

* The `std::arch::{x86, x86_64}` modules and the intrinsics contained inside.
* The `is_x86_feature_detected!` macro in the standard library
* The `#[target_feature(enable = "...")]` attribute
* The `#[cfg(target_feature = "...")]` matcher

Stabilization of the module and intrinsics were primarily done in
rust-lang/stdarch#414 and the two attribute stabilizations are done in
this commit. The standard library is also tweaked a bit with the new way that
stdsimd is integrated.

Note that other architectures like `std::arch::arm` are not stabilized as part
of this commit, they will likely stabilize in the future after they've been
implemented and fleshed out. Similarly the `std::simd` module is also not being
stabilized in this commit, only `std::arch`. Finally, nothing related to `__m64`
is stabilized in this commit either (MMX), only SSE and up types and intrinsics
are stabilized.

Closes #29717
Closes #44839
Closes #48556
  • Loading branch information
bors committed Apr 17, 2018
2 parents 94516c5 + 1217d70 commit 186db76
Show file tree
Hide file tree
Showing 18 changed files with 243 additions and 166 deletions.
29 changes: 26 additions & 3 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@
#![feature(asm)]
#![feature(associated_type_defaults)]
#![feature(attr_literals)]
#![feature(cfg_target_feature)]
#![feature(cfg_target_has_atomic)]
#![feature(concat_idents)]
#![feature(const_fn)]
Expand Down Expand Up @@ -96,11 +95,21 @@
#![feature(specialization)]
#![feature(staged_api)]
#![feature(stmt_expr_attributes)]
#![feature(target_feature)]
#![feature(unboxed_closures)]
#![feature(untagged_unions)]
#![feature(unwind_attributes)]

#![cfg_attr(not(stage0), feature(mmx_target_feature))]
#![cfg_attr(not(stage0), feature(tbm_target_feature))]
#![cfg_attr(not(stage0), feature(sse4a_target_feature))]
#![cfg_attr(not(stage0), feature(arm_target_feature))]
#![cfg_attr(not(stage0), feature(powerpc_target_feature))]
#![cfg_attr(not(stage0), feature(mips_target_feature))]
#![cfg_attr(not(stage0), feature(aarch64_target_feature))]

#![cfg_attr(stage0, feature(target_feature))]
#![cfg_attr(stage0, feature(cfg_target_feature))]

#[prelude_import]
#[allow(unused)]
use prelude::v1::*;
Expand Down Expand Up @@ -204,6 +213,20 @@ mod unit;
// things like SIMD and such. Note that the actual source for all this lies in a
// different repository, rust-lang-nursery/stdsimd. That's why the setup here is
// a bit wonky.
#[allow(unused_macros)]
macro_rules! test_v16 { ($item:item) => {}; }
#[allow(unused_macros)]
macro_rules! test_v32 { ($item:item) => {}; }
#[allow(unused_macros)]
macro_rules! test_v64 { ($item:item) => {}; }
#[allow(unused_macros)]
macro_rules! test_v128 { ($item:item) => {}; }
#[allow(unused_macros)]
macro_rules! test_v256 { ($item:item) => {}; }
#[allow(unused_macros)]
macro_rules! test_v512 { ($item:item) => {}; }
#[allow(unused_macros)]
macro_rules! vector_impl { ($([$f:ident, $($args:tt)*]),*) => { $($f!($($args)*);)* } }
#[path = "../stdsimd/coresimd/mod.rs"]
#[allow(missing_docs, missing_debug_implementations, dead_code)]
#[unstable(feature = "stdsimd", issue = "48556")]
Expand All @@ -213,6 +236,6 @@ mod coresimd;
#[unstable(feature = "stdsimd", issue = "48556")]
#[cfg(not(stage0))]
pub use coresimd::simd;
#[unstable(feature = "stdsimd", issue = "48556")]
#[stable(feature = "simd_arch", since = "1.27.0")]
#[cfg(not(stage0))]
pub use coresimd::arch;
2 changes: 1 addition & 1 deletion src/librustc/ty/maps/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ define_maps! { <'tcx>
substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,

[] fn target_features_whitelist:
target_features_whitelist_node(CrateNum) -> Lrc<FxHashSet<String>>,
target_features_whitelist_node(CrateNum) -> Lrc<FxHashMap<String, Option<String>>>,

// Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning.
[] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>)
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_trans/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,12 @@ pub fn provide(providers: &mut Providers) {
// rustdoc needs to be able to document functions that use all the features, so
// whitelist them all
Lrc::new(llvm_util::all_known_features()
.map(|c| c.to_string())
.map(|(a, b)| (a.to_string(), b.map(|s| s.to_string())))
.collect())
} else {
Lrc::new(llvm_util::target_feature_whitelist(tcx.sess)
.iter()
.map(|c| c.to_string())
.map(|&(a, b)| (a.to_string(), b.map(|s| s.to_string())))
.collect())
}
};
Expand Down
123 changes: 94 additions & 29 deletions src/librustc_trans/llvm_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use rustc::session::Session;
use rustc::session::config::PrintRequest;
use libc::c_int;
use std::ffi::CString;
use syntax::feature_gate::UnstableFeatures;

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;
Expand Down Expand Up @@ -82,40 +83,95 @@ unsafe fn configure_llvm(sess: &Session) {
// to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes.

const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"];

const AARCH64_WHITELIST: &'static [&'static str] = &["fp", "neon", "sve", "crc", "crypto",
"ras", "lse", "rdm", "fp16", "rcpc",
"dotprod", "v8.1a", "v8.2a", "v8.3a"];

const X86_WHITELIST: &'static [&'static str] = &["aes", "avx", "avx2", "avx512bw",
"avx512cd", "avx512dq", "avx512er",
"avx512f", "avx512ifma", "avx512pf",
"avx512vbmi", "avx512vl", "avx512vpopcntdq",
"bmi1", "bmi2", "fma", "fxsr",
"lzcnt", "mmx", "pclmulqdq",
"popcnt", "rdrand", "rdseed",
"sha",
"sse", "sse2", "sse3", "sse4.1",
"sse4.2", "sse4a", "ssse3",
"tbm", "xsave", "xsavec",
"xsaveopt", "xsaves"];

const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"];

const POWERPC_WHITELIST: &'static [&'static str] = &["altivec",
"power8-altivec", "power9-altivec",
"power8-vector", "power9-vector",
"vsx"];

const MIPS_WHITELIST: &'static [&'static str] = &["fp64", "msa"];
const ARM_WHITELIST: &[(&str, Option<&str>)] = &[
("neon", Some("arm_target_feature")),
("v7", Some("arm_target_feature")),
("vfp2", Some("arm_target_feature")),
("vfp3", Some("arm_target_feature")),
("vfp4", Some("arm_target_feature")),
];

const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[
("fp", Some("aarch64_target_feature")),
("neon", Some("aarch64_target_feature")),
("sve", Some("aarch64_target_feature")),
("crc", Some("aarch64_target_feature")),
("crypto", Some("aarch64_target_feature")),
("ras", Some("aarch64_target_feature")),
("lse", Some("aarch64_target_feature")),
("rdm", Some("aarch64_target_feature")),
("fp16", Some("aarch64_target_feature")),
("rcpc", Some("aarch64_target_feature")),
("dotprod", Some("aarch64_target_feature")),
("v8.1a", Some("aarch64_target_feature")),
("v8.2a", Some("aarch64_target_feature")),
("v8.3a", Some("aarch64_target_feature")),
];

const X86_WHITELIST: &[(&str, Option<&str>)] = &[
("aes", None),
("avx", None),
("avx2", None),
("avx512bw", Some("avx512_target_feature")),
("avx512cd", Some("avx512_target_feature")),
("avx512dq", Some("avx512_target_feature")),
("avx512er", Some("avx512_target_feature")),
("avx512f", Some("avx512_target_feature")),
("avx512ifma", Some("avx512_target_feature")),
("avx512pf", Some("avx512_target_feature")),
("avx512vbmi", Some("avx512_target_feature")),
("avx512vl", Some("avx512_target_feature")),
("avx512vpopcntdq", Some("avx512_target_feature")),
("bmi1", None),
("bmi2", None),
("fma", None),
("fxsr", None),
("lzcnt", None),
("mmx", Some("mmx_target_feature")),
("pclmulqdq", None),
("popcnt", None),
("rdrand", None),
("rdseed", None),
("sha", None),
("sse", None),
("sse2", None),
("sse3", None),
("sse4.1", None),
("sse4.2", None),
("sse4a", Some("sse4a_target_feature")),
("ssse3", None),
("tbm", Some("tbm_target_feature")),
("xsave", None),
("xsavec", None),
("xsaveopt", None),
("xsaves", None),
];

const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[
("hvx", Some("hexagon_target_feature")),
("hvx-double", Some("hexagon_target_feature")),
];

const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[
("altivec", Some("powerpc_target_feature")),
("power8-altivec", Some("powerpc_target_feature")),
("power9-altivec", Some("powerpc_target_feature")),
("power8-vector", Some("powerpc_target_feature")),
("power9-vector", Some("powerpc_target_feature")),
("vsx", Some("powerpc_target_feature")),
];

const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[
("fp64", Some("mips_target_feature")),
("msa", Some("mips_target_feature")),
];

/// When rustdoc is running, provide a list of all known features so that all their respective
/// primtives may be documented.
///
/// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
/// iterator!
pub fn all_known_features() -> impl Iterator<Item=&'static str> {
pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<&'static str>)> {
ARM_WHITELIST.iter().cloned()
.chain(AARCH64_WHITELIST.iter().cloned())
.chain(X86_WHITELIST.iter().cloned())
Expand Down Expand Up @@ -144,6 +200,13 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
let target_machine = create_target_machine(sess, true);
target_feature_whitelist(sess)
.iter()
.filter_map(|&(feature, gate)| {
if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() {
Some(feature)
} else {
None
}
})
.filter(|feature| {
let llvm_feature = to_llvm_feature(sess, feature);
let cstr = CString::new(llvm_feature).unwrap();
Expand All @@ -152,7 +215,9 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
.map(|feature| Symbol::intern(feature)).collect()
}

pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] {
pub fn target_feature_whitelist(sess: &Session)
-> &'static [(&'static str, Option<&'static str>)]
{
match &*sess.target.target.arch {
"arm" => ARM_WHITELIST,
"aarch64" => AARCH64_WHITELIST,
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_trans_utils/trans_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use rustc::middle::cstore::EncodedMetadata;
use rustc::middle::cstore::MetadataLoader;
use rustc::dep_graph::DepGraph;
use rustc_back::target::Target;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::fx::FxHashMap;
use rustc_mir::monomorphize::collector;
use link::{build_link_meta, out_filename};

Expand Down Expand Up @@ -203,7 +203,7 @@ impl TransCrate for MetadataOnlyTransCrate {
::symbol_names::provide(providers);

providers.target_features_whitelist = |_tcx, _cnum| {
Lrc::new(FxHashSet()) // Just a dummy
Lrc::new(FxHashMap()) // Just a dummy
};
}
fn provide_extern(&self, _providers: &mut Providers) {}
Expand Down
87 changes: 54 additions & 33 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ use rustc::ty::maps::Providers;
use rustc::ty::util::IntTypeExt;
use rustc::ty::util::Discr;
use rustc::util::captures::Captures;
use rustc::util::nodemap::{FxHashSet, FxHashMap};
use rustc::util::nodemap::FxHashMap;

use syntax::{abi, ast};
use syntax::ast::MetaItemKind;
use syntax::attr::{InlineAttr, list_contains_name, mark_used};
use syntax::codemap::Spanned;
use syntax::symbol::{Symbol, keywords};
use syntax::feature_gate;
use syntax_pos::{Span, DUMMY_SP};

use rustc::hir::{self, map as hir_map, TransFnAttrs, TransFnAttrFlags, Unsafety};
Expand Down Expand Up @@ -1682,7 +1683,7 @@ fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
fn from_target_feature(
tcx: TyCtxt,
attr: &ast::Attribute,
whitelist: &FxHashSet<String>,
whitelist: &FxHashMap<String, Option<String>>,
target_features: &mut Vec<Symbol>,
) {
let list = match attr.meta_item_list() {
Expand All @@ -1694,41 +1695,75 @@ fn from_target_feature(
return
}
};

let rust_features = tcx.features();
for item in list {
// Only `enable = ...` is accepted in the meta item list
if !item.check_name("enable") {
let msg = "#[target_feature(..)] only accepts sub-keys of `enable` \
currently";
tcx.sess.span_err(item.span, &msg);
continue
}

// Must be of the form `enable = "..."` ( a string)
let value = match item.value_str() {
Some(list) => list,
Some(value) => value,
None => {
let msg = "#[target_feature] attribute must be of the form \
#[target_feature(enable = \"..\")]";
tcx.sess.span_err(item.span, &msg);
continue
}
};
let value = value.as_str();
for feature in value.split(',') {
if whitelist.contains(feature) {
target_features.push(Symbol::intern(feature));
continue
}

let msg = format!("the feature named `{}` is not valid for \
this target", feature);
let mut err = tcx.sess.struct_span_err(item.span, &msg);

if feature.starts_with("+") {
let valid = whitelist.contains(&feature[1..]);
if valid {
err.help("consider removing the leading `+` in the feature name");
// We allow comma separation to enable multiple features
for feature in value.as_str().split(',') {

// Only allow whitelisted features per platform
let feature_gate = match whitelist.get(feature) {
Some(g) => g,
None => {
let msg = format!("the feature named `{}` is not valid for \
this target", feature);
let mut err = tcx.sess.struct_span_err(item.span, &msg);

if feature.starts_with("+") {
let valid = whitelist.contains_key(&feature[1..]);
if valid {
err.help("consider removing the leading `+` in the feature name");
}
}
err.emit();
continue
}
};

// Only allow features whose feature gates have been enabled
let allowed = match feature_gate.as_ref().map(|s| &**s) {
Some("arm_target_feature") => rust_features.arm_target_feature,
Some("aarch64_target_feature") => rust_features.aarch64_target_feature,
Some("hexagon_target_feature") => rust_features.hexagon_target_feature,
Some("powerpc_target_feature") => rust_features.powerpc_target_feature,
Some("mips_target_feature") => rust_features.mips_target_feature,
Some("avx512_target_feature") => rust_features.avx512_target_feature,
Some("mmx_target_feature") => rust_features.mmx_target_feature,
Some("sse4a_target_feature") => rust_features.sse4a_target_feature,
Some("tbm_target_feature") => rust_features.tbm_target_feature,
Some(name) => bug!("unknown target feature gate {}", name),
None => true,
};
if !allowed {
feature_gate::emit_feature_err(
&tcx.sess.parse_sess,
feature_gate.as_ref().unwrap(),
item.span,
feature_gate::GateIssue::Language,
&format!("the target feature `{}` is currently unstable",
feature),
);
continue
}
err.emit();
target_features.push(Symbol::intern(feature));
}
}
}
Expand Down Expand Up @@ -1835,20 +1870,6 @@ fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAt
.emit();
}
} else if attr.check_name("target_feature") {
// handle deprecated #[target_feature = "..."]
if let Some(val) = attr.value_str() {
for feat in val.as_str().split(",").map(|f| f.trim()) {
if !feat.is_empty() && !feat.contains('\0') {
trans_fn_attrs.target_features.push(Symbol::intern(feat));
}
}
let msg = "#[target_feature = \"..\"] is deprecated and will \
eventually be removed, use \
#[target_feature(enable = \"..\")] instead";
tcx.sess.span_warn(attr.span, &msg);
continue
}

if tcx.fn_sig(id).unsafety() == Unsafety::Normal {
let msg = "#[target_feature(..)] can only be applied to \
`unsafe` function";
Expand Down
Loading

0 comments on commit 186db76

Please sign in to comment.