diff options
| author | bors <bors@rust-lang.org> | 2016-12-03 17:41:14 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2016-12-03 17:41:14 +0000 |
| commit | 2cdbd5eb4255974db204819f9aa49c00b15a6d23 (patch) | |
| tree | 700af30689a3fd50162761b8c5c2f9eff8c35808 | |
| parent | 890085450a495678622178a471afd630fe15f0f5 (diff) | |
| parent | 80ef1dbf2d51d2f2fd039d98a9150d2614e775b0 (diff) | |
Auto merge of #38079 - BurntSushi:attrtarget, r=alexcrichton
Add new #[target_feature = "..."] attribute.
This commit adds a new attribute that instructs the compiler to emit
target specific code for a single function. For example, the following
function is permitted to use instructions that are part of SSE 4.2:
#[target_feature = "+sse4.2"]
fn foo() { ... }
In particular, use of this attribute does not require setting the
-C target-feature or -C target-cpu options on rustc.
This attribute does not have any protections built into it. For example,
nothing stops one from calling the above `foo` function on hosts without
SSE 4.2 support. Doing so may result in a SIGILL.
I've also expanded the x86 target feature whitelist.
| -rw-r--r-- | src/librustc_driver/target_features.rs | 3 | ||||
| -rw-r--r-- | src/librustc_llvm/lib.rs | 8 | ||||
| -rw-r--r-- | src/librustc_trans/attributes.rs | 30 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 7 | ||||
| -rw-r--r-- | src/test/compile-fail/gated-target_feature.rs | 13 |
5 files changed, 50 insertions, 11 deletions
diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs index 876323d599e..124e7aafcc5 100644 --- a/src/librustc_driver/target_features.rs +++ b/src/librustc_driver/target_features.rs @@ -24,7 +24,8 @@ const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "vfp2\0", "vfp3\0", " const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0", "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0", - "ssse3\0", "tbm\0"]; + "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0", + "sse4a\0"]; /// Add `target_feature = "..."` cfgs for a variety of platform /// specific features (SSE, NEON etc.). diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 0229776c948..0effceb0425 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -66,13 +66,13 @@ impl LLVMRustResult { pub fn AddFunctionAttrStringValue(llfn: ValueRef, idx: AttributePlace, - attr: &'static str, - value: &'static str) { + attr: &CStr, + value: &CStr) { unsafe { LLVMRustAddFunctionAttrStringValue(llfn, idx.as_uint(), - attr.as_ptr() as *const _, - value.as_ptr() as *const _) + attr.as_ptr(), + value.as_ptr()) } } diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index f1e90419a49..efdd1b736f0 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -9,6 +9,8 @@ // except according to those terms. //! Set and unset common attributes on LLVM values. +use std::ffi::{CStr, CString}; + use llvm::{self, Attribute, ValueRef}; use llvm::AttributePlace::Function; pub use syntax::attr::InlineAttr; @@ -61,10 +63,8 @@ pub fn set_frame_pointer_elimination(ccx: &CrateContext, llfn: ValueRef) { // parameter. if ccx.sess().must_not_eliminate_frame_pointers() { llvm::AddFunctionAttrStringValue( - llfn, - llvm::AttributePlace::Function, - "no-frame-pointer-elim\0", - "true\0") + llfn, llvm::AttributePlace::Function, + cstr("no-frame-pointer-elim\0"), cstr("true\0")); } } @@ -75,9 +75,17 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe inline(llfn, find_inline_attr(Some(ccx.sess().diagnostic()), attrs)); set_frame_pointer_elimination(ccx, llfn); - + let mut target_features = vec![]; for attr in attrs { - if attr.check_name("cold") { + if attr.check_name("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') { + target_features.push(feat.to_string()); + } + } + } + } else if attr.check_name("cold") { Attribute::Cold.apply_llfn(Function, llfn); } else if attr.check_name("naked") { naked(llfn, true); @@ -88,4 +96,14 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe unwind(llfn, true); } } + if !target_features.is_empty() { + let val = CString::new(target_features.join(",")).unwrap(); + llvm::AddFunctionAttrStringValue( + llfn, llvm::AttributePlace::Function, + cstr("target-features\0"), &val); + } +} + +fn cstr(s: &'static str) -> &CStr { + CStr::from_bytes_with_nul(s.as_bytes()).expect("null-terminated string") } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 2a745e979a7..1b2c2869cb8 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -316,6 +316,9 @@ declare_features! ( // Allows `break {expr}` with a value inside `loop`s. (active, loop_break_value, "1.14.0", Some(37339)), + + // Allows #[target_feature(...)] + (active, target_feature, "1.15.0", None), ); declare_features! ( @@ -664,6 +667,10 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "the `#[naked]` attribute \ is an experimental feature", cfg_fn!(naked_functions))), + ("target_feature", Whitelisted, Gated( + Stability::Unstable, "target_feature", + "the `#[target_feature]` attribute is an experimental feature", + cfg_fn!(target_feature))), ("export_name", Whitelisted, Ungated), ("inline", Whitelisted, Ungated), ("link", Whitelisted, Ungated), diff --git a/src/test/compile-fail/gated-target_feature.rs b/src/test/compile-fail/gated-target_feature.rs new file mode 100644 index 00000000000..da2e41a0f5e --- /dev/null +++ b/src/test/compile-fail/gated-target_feature.rs @@ -0,0 +1,13 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[target_feature = "+sse2"] +//~^ the `#[target_feature]` attribute is an experimental feature +fn foo() {} |
