Skip to content

Commit 186db76

Browse files
committed
Auto merge of #49664 - alexcrichton:stable-simd, r=BurntSushi
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
2 parents 94516c5 + 1217d70 commit 186db76

18 files changed

+243
-166
lines changed

src/libcore/lib.rs

+26-3
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@
6868
#![feature(asm)]
6969
#![feature(associated_type_defaults)]
7070
#![feature(attr_literals)]
71-
#![feature(cfg_target_feature)]
7271
#![feature(cfg_target_has_atomic)]
7372
#![feature(concat_idents)]
7473
#![feature(const_fn)]
@@ -96,11 +95,21 @@
9695
#![feature(specialization)]
9796
#![feature(staged_api)]
9897
#![feature(stmt_expr_attributes)]
99-
#![feature(target_feature)]
10098
#![feature(unboxed_closures)]
10199
#![feature(untagged_unions)]
102100
#![feature(unwind_attributes)]
103101

102+
#![cfg_attr(not(stage0), feature(mmx_target_feature))]
103+
#![cfg_attr(not(stage0), feature(tbm_target_feature))]
104+
#![cfg_attr(not(stage0), feature(sse4a_target_feature))]
105+
#![cfg_attr(not(stage0), feature(arm_target_feature))]
106+
#![cfg_attr(not(stage0), feature(powerpc_target_feature))]
107+
#![cfg_attr(not(stage0), feature(mips_target_feature))]
108+
#![cfg_attr(not(stage0), feature(aarch64_target_feature))]
109+
110+
#![cfg_attr(stage0, feature(target_feature))]
111+
#![cfg_attr(stage0, feature(cfg_target_feature))]
112+
104113
#[prelude_import]
105114
#[allow(unused)]
106115
use prelude::v1::*;
@@ -204,6 +213,20 @@ mod unit;
204213
// things like SIMD and such. Note that the actual source for all this lies in a
205214
// different repository, rust-lang-nursery/stdsimd. That's why the setup here is
206215
// a bit wonky.
216+
#[allow(unused_macros)]
217+
macro_rules! test_v16 { ($item:item) => {}; }
218+
#[allow(unused_macros)]
219+
macro_rules! test_v32 { ($item:item) => {}; }
220+
#[allow(unused_macros)]
221+
macro_rules! test_v64 { ($item:item) => {}; }
222+
#[allow(unused_macros)]
223+
macro_rules! test_v128 { ($item:item) => {}; }
224+
#[allow(unused_macros)]
225+
macro_rules! test_v256 { ($item:item) => {}; }
226+
#[allow(unused_macros)]
227+
macro_rules! test_v512 { ($item:item) => {}; }
228+
#[allow(unused_macros)]
229+
macro_rules! vector_impl { ($([$f:ident, $($args:tt)*]),*) => { $($f!($($args)*);)* } }
207230
#[path = "../stdsimd/coresimd/mod.rs"]
208231
#[allow(missing_docs, missing_debug_implementations, dead_code)]
209232
#[unstable(feature = "stdsimd", issue = "48556")]
@@ -213,6 +236,6 @@ mod coresimd;
213236
#[unstable(feature = "stdsimd", issue = "48556")]
214237
#[cfg(not(stage0))]
215238
pub use coresimd::simd;
216-
#[unstable(feature = "stdsimd", issue = "48556")]
239+
#[stable(feature = "simd_arch", since = "1.27.0")]
217240
#[cfg(not(stage0))]
218241
pub use coresimd::arch;

src/librustc/ty/maps/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ define_maps! { <'tcx>
437437
substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
438438

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

442442
// Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning.
443443
[] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>)

src/librustc_trans/attributes.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,12 @@ pub fn provide(providers: &mut Providers) {
174174
// rustdoc needs to be able to document functions that use all the features, so
175175
// whitelist them all
176176
Lrc::new(llvm_util::all_known_features()
177-
.map(|c| c.to_string())
177+
.map(|(a, b)| (a.to_string(), b.map(|s| s.to_string())))
178178
.collect())
179179
} else {
180180
Lrc::new(llvm_util::target_feature_whitelist(tcx.sess)
181181
.iter()
182-
.map(|c| c.to_string())
182+
.map(|&(a, b)| (a.to_string(), b.map(|s| s.to_string())))
183183
.collect())
184184
}
185185
};

src/librustc_trans/llvm_util.rs

+94-29
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc::session::Session;
1515
use rustc::session::config::PrintRequest;
1616
use libc::c_int;
1717
use std::ffi::CString;
18+
use syntax::feature_gate::UnstableFeatures;
1819

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

85-
const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"];
86-
87-
const AARCH64_WHITELIST: &'static [&'static str] = &["fp", "neon", "sve", "crc", "crypto",
88-
"ras", "lse", "rdm", "fp16", "rcpc",
89-
"dotprod", "v8.1a", "v8.2a", "v8.3a"];
90-
91-
const X86_WHITELIST: &'static [&'static str] = &["aes", "avx", "avx2", "avx512bw",
92-
"avx512cd", "avx512dq", "avx512er",
93-
"avx512f", "avx512ifma", "avx512pf",
94-
"avx512vbmi", "avx512vl", "avx512vpopcntdq",
95-
"bmi1", "bmi2", "fma", "fxsr",
96-
"lzcnt", "mmx", "pclmulqdq",
97-
"popcnt", "rdrand", "rdseed",
98-
"sha",
99-
"sse", "sse2", "sse3", "sse4.1",
100-
"sse4.2", "sse4a", "ssse3",
101-
"tbm", "xsave", "xsavec",
102-
"xsaveopt", "xsaves"];
103-
104-
const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"];
105-
106-
const POWERPC_WHITELIST: &'static [&'static str] = &["altivec",
107-
"power8-altivec", "power9-altivec",
108-
"power8-vector", "power9-vector",
109-
"vsx"];
110-
111-
const MIPS_WHITELIST: &'static [&'static str] = &["fp64", "msa"];
86+
const ARM_WHITELIST: &[(&str, Option<&str>)] = &[
87+
("neon", Some("arm_target_feature")),
88+
("v7", Some("arm_target_feature")),
89+
("vfp2", Some("arm_target_feature")),
90+
("vfp3", Some("arm_target_feature")),
91+
("vfp4", Some("arm_target_feature")),
92+
];
93+
94+
const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[
95+
("fp", Some("aarch64_target_feature")),
96+
("neon", Some("aarch64_target_feature")),
97+
("sve", Some("aarch64_target_feature")),
98+
("crc", Some("aarch64_target_feature")),
99+
("crypto", Some("aarch64_target_feature")),
100+
("ras", Some("aarch64_target_feature")),
101+
("lse", Some("aarch64_target_feature")),
102+
("rdm", Some("aarch64_target_feature")),
103+
("fp16", Some("aarch64_target_feature")),
104+
("rcpc", Some("aarch64_target_feature")),
105+
("dotprod", Some("aarch64_target_feature")),
106+
("v8.1a", Some("aarch64_target_feature")),
107+
("v8.2a", Some("aarch64_target_feature")),
108+
("v8.3a", Some("aarch64_target_feature")),
109+
];
110+
111+
const X86_WHITELIST: &[(&str, Option<&str>)] = &[
112+
("aes", None),
113+
("avx", None),
114+
("avx2", None),
115+
("avx512bw", Some("avx512_target_feature")),
116+
("avx512cd", Some("avx512_target_feature")),
117+
("avx512dq", Some("avx512_target_feature")),
118+
("avx512er", Some("avx512_target_feature")),
119+
("avx512f", Some("avx512_target_feature")),
120+
("avx512ifma", Some("avx512_target_feature")),
121+
("avx512pf", Some("avx512_target_feature")),
122+
("avx512vbmi", Some("avx512_target_feature")),
123+
("avx512vl", Some("avx512_target_feature")),
124+
("avx512vpopcntdq", Some("avx512_target_feature")),
125+
("bmi1", None),
126+
("bmi2", None),
127+
("fma", None),
128+
("fxsr", None),
129+
("lzcnt", None),
130+
("mmx", Some("mmx_target_feature")),
131+
("pclmulqdq", None),
132+
("popcnt", None),
133+
("rdrand", None),
134+
("rdseed", None),
135+
("sha", None),
136+
("sse", None),
137+
("sse2", None),
138+
("sse3", None),
139+
("sse4.1", None),
140+
("sse4.2", None),
141+
("sse4a", Some("sse4a_target_feature")),
142+
("ssse3", None),
143+
("tbm", Some("tbm_target_feature")),
144+
("xsave", None),
145+
("xsavec", None),
146+
("xsaveopt", None),
147+
("xsaves", None),
148+
];
149+
150+
const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[
151+
("hvx", Some("hexagon_target_feature")),
152+
("hvx-double", Some("hexagon_target_feature")),
153+
];
154+
155+
const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[
156+
("altivec", Some("powerpc_target_feature")),
157+
("power8-altivec", Some("powerpc_target_feature")),
158+
("power9-altivec", Some("powerpc_target_feature")),
159+
("power8-vector", Some("powerpc_target_feature")),
160+
("power9-vector", Some("powerpc_target_feature")),
161+
("vsx", Some("powerpc_target_feature")),
162+
];
163+
164+
const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[
165+
("fp64", Some("mips_target_feature")),
166+
("msa", Some("mips_target_feature")),
167+
];
112168

113169
/// When rustdoc is running, provide a list of all known features so that all their respective
114170
/// primtives may be documented.
115171
///
116172
/// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
117173
/// iterator!
118-
pub fn all_known_features() -> impl Iterator<Item=&'static str> {
174+
pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<&'static str>)> {
119175
ARM_WHITELIST.iter().cloned()
120176
.chain(AARCH64_WHITELIST.iter().cloned())
121177
.chain(X86_WHITELIST.iter().cloned())
@@ -144,6 +200,13 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
144200
let target_machine = create_target_machine(sess, true);
145201
target_feature_whitelist(sess)
146202
.iter()
203+
.filter_map(|&(feature, gate)| {
204+
if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() {
205+
Some(feature)
206+
} else {
207+
None
208+
}
209+
})
147210
.filter(|feature| {
148211
let llvm_feature = to_llvm_feature(sess, feature);
149212
let cstr = CString::new(llvm_feature).unwrap();
@@ -152,7 +215,9 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
152215
.map(|feature| Symbol::intern(feature)).collect()
153216
}
154217

155-
pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] {
218+
pub fn target_feature_whitelist(sess: &Session)
219+
-> &'static [(&'static str, Option<&'static str>)]
220+
{
156221
match &*sess.target.target.arch {
157222
"arm" => ARM_WHITELIST,
158223
"aarch64" => AARCH64_WHITELIST,

src/librustc_trans_utils/trans_crate.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ use rustc::middle::cstore::EncodedMetadata;
4444
use rustc::middle::cstore::MetadataLoader;
4545
use rustc::dep_graph::DepGraph;
4646
use rustc_back::target::Target;
47-
use rustc_data_structures::fx::FxHashSet;
47+
use rustc_data_structures::fx::FxHashMap;
4848
use rustc_mir::monomorphize::collector;
4949
use link::{build_link_meta, out_filename};
5050

@@ -203,7 +203,7 @@ impl TransCrate for MetadataOnlyTransCrate {
203203
::symbol_names::provide(providers);
204204

205205
providers.target_features_whitelist = |_tcx, _cnum| {
206-
Lrc::new(FxHashSet()) // Just a dummy
206+
Lrc::new(FxHashMap()) // Just a dummy
207207
};
208208
}
209209
fn provide_extern(&self, _providers: &mut Providers) {}

src/librustc_typeck/collect.rs

+54-33
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,14 @@ use rustc::ty::maps::Providers;
3737
use rustc::ty::util::IntTypeExt;
3838
use rustc::ty::util::Discr;
3939
use rustc::util::captures::Captures;
40-
use rustc::util::nodemap::{FxHashSet, FxHashMap};
40+
use rustc::util::nodemap::FxHashMap;
4141

4242
use syntax::{abi, ast};
4343
use syntax::ast::MetaItemKind;
4444
use syntax::attr::{InlineAttr, list_contains_name, mark_used};
4545
use syntax::codemap::Spanned;
4646
use syntax::symbol::{Symbol, keywords};
47+
use syntax::feature_gate;
4748
use syntax_pos::{Span, DUMMY_SP};
4849

4950
use rustc::hir::{self, map as hir_map, TransFnAttrs, TransFnAttrFlags, Unsafety};
@@ -1682,7 +1683,7 @@ fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
16821683
fn from_target_feature(
16831684
tcx: TyCtxt,
16841685
attr: &ast::Attribute,
1685-
whitelist: &FxHashSet<String>,
1686+
whitelist: &FxHashMap<String, Option<String>>,
16861687
target_features: &mut Vec<Symbol>,
16871688
) {
16881689
let list = match attr.meta_item_list() {
@@ -1694,41 +1695,75 @@ fn from_target_feature(
16941695
return
16951696
}
16961697
};
1697-
1698+
let rust_features = tcx.features();
16981699
for item in list {
1700+
// Only `enable = ...` is accepted in the meta item list
16991701
if !item.check_name("enable") {
17001702
let msg = "#[target_feature(..)] only accepts sub-keys of `enable` \
17011703
currently";
17021704
tcx.sess.span_err(item.span, &msg);
17031705
continue
17041706
}
1707+
1708+
// Must be of the form `enable = "..."` ( a string)
17051709
let value = match item.value_str() {
1706-
Some(list) => list,
1710+
Some(value) => value,
17071711
None => {
17081712
let msg = "#[target_feature] attribute must be of the form \
17091713
#[target_feature(enable = \"..\")]";
17101714
tcx.sess.span_err(item.span, &msg);
17111715
continue
17121716
}
17131717
};
1714-
let value = value.as_str();
1715-
for feature in value.split(',') {
1716-
if whitelist.contains(feature) {
1717-
target_features.push(Symbol::intern(feature));
1718-
continue
1719-
}
1720-
1721-
let msg = format!("the feature named `{}` is not valid for \
1722-
this target", feature);
1723-
let mut err = tcx.sess.struct_span_err(item.span, &msg);
17241718

1725-
if feature.starts_with("+") {
1726-
let valid = whitelist.contains(&feature[1..]);
1727-
if valid {
1728-
err.help("consider removing the leading `+` in the feature name");
1719+
// We allow comma separation to enable multiple features
1720+
for feature in value.as_str().split(',') {
1721+
1722+
// Only allow whitelisted features per platform
1723+
let feature_gate = match whitelist.get(feature) {
1724+
Some(g) => g,
1725+
None => {
1726+
let msg = format!("the feature named `{}` is not valid for \
1727+
this target", feature);
1728+
let mut err = tcx.sess.struct_span_err(item.span, &msg);
1729+
1730+
if feature.starts_with("+") {
1731+
let valid = whitelist.contains_key(&feature[1..]);
1732+
if valid {
1733+
err.help("consider removing the leading `+` in the feature name");
1734+
}
1735+
}
1736+
err.emit();
1737+
continue
17291738
}
1739+
};
1740+
1741+
// Only allow features whose feature gates have been enabled
1742+
let allowed = match feature_gate.as_ref().map(|s| &**s) {
1743+
Some("arm_target_feature") => rust_features.arm_target_feature,
1744+
Some("aarch64_target_feature") => rust_features.aarch64_target_feature,
1745+
Some("hexagon_target_feature") => rust_features.hexagon_target_feature,
1746+
Some("powerpc_target_feature") => rust_features.powerpc_target_feature,
1747+
Some("mips_target_feature") => rust_features.mips_target_feature,
1748+
Some("avx512_target_feature") => rust_features.avx512_target_feature,
1749+
Some("mmx_target_feature") => rust_features.mmx_target_feature,
1750+
Some("sse4a_target_feature") => rust_features.sse4a_target_feature,
1751+
Some("tbm_target_feature") => rust_features.tbm_target_feature,
1752+
Some(name) => bug!("unknown target feature gate {}", name),
1753+
None => true,
1754+
};
1755+
if !allowed {
1756+
feature_gate::emit_feature_err(
1757+
&tcx.sess.parse_sess,
1758+
feature_gate.as_ref().unwrap(),
1759+
item.span,
1760+
feature_gate::GateIssue::Language,
1761+
&format!("the target feature `{}` is currently unstable",
1762+
feature),
1763+
);
1764+
continue
17301765
}
1731-
err.emit();
1766+
target_features.push(Symbol::intern(feature));
17321767
}
17331768
}
17341769
}
@@ -1835,20 +1870,6 @@ fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAt
18351870
.emit();
18361871
}
18371872
} else if attr.check_name("target_feature") {
1838-
// handle deprecated #[target_feature = "..."]
1839-
if let Some(val) = attr.value_str() {
1840-
for feat in val.as_str().split(",").map(|f| f.trim()) {
1841-
if !feat.is_empty() && !feat.contains('\0') {
1842-
trans_fn_attrs.target_features.push(Symbol::intern(feat));
1843-
}
1844-
}
1845-
let msg = "#[target_feature = \"..\"] is deprecated and will \
1846-
eventually be removed, use \
1847-
#[target_feature(enable = \"..\")] instead";
1848-
tcx.sess.span_warn(attr.span, &msg);
1849-
continue
1850-
}
1851-
18521873
if tcx.fn_sig(id).unsafety() == Unsafety::Normal {
18531874
let msg = "#[target_feature(..)] can only be applied to \
18541875
`unsafe` function";

0 commit comments

Comments
 (0)