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.
This commit is contained in:
commit
2cdbd5eb42
5 changed files with 50 additions and 11 deletions
|
@ -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",
|
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",
|
"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
|
/// Add `target_feature = "..."` cfgs for a variety of platform
|
||||||
/// specific features (SSE, NEON etc.).
|
/// specific features (SSE, NEON etc.).
|
||||||
|
|
|
@ -66,13 +66,13 @@ impl LLVMRustResult {
|
||||||
|
|
||||||
pub fn AddFunctionAttrStringValue(llfn: ValueRef,
|
pub fn AddFunctionAttrStringValue(llfn: ValueRef,
|
||||||
idx: AttributePlace,
|
idx: AttributePlace,
|
||||||
attr: &'static str,
|
attr: &CStr,
|
||||||
value: &'static str) {
|
value: &CStr) {
|
||||||
unsafe {
|
unsafe {
|
||||||
LLVMRustAddFunctionAttrStringValue(llfn,
|
LLVMRustAddFunctionAttrStringValue(llfn,
|
||||||
idx.as_uint(),
|
idx.as_uint(),
|
||||||
attr.as_ptr() as *const _,
|
attr.as_ptr(),
|
||||||
value.as_ptr() as *const _)
|
value.as_ptr())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
//! Set and unset common attributes on LLVM values.
|
//! Set and unset common attributes on LLVM values.
|
||||||
|
|
||||||
|
use std::ffi::{CStr, CString};
|
||||||
|
|
||||||
use llvm::{self, Attribute, ValueRef};
|
use llvm::{self, Attribute, ValueRef};
|
||||||
use llvm::AttributePlace::Function;
|
use llvm::AttributePlace::Function;
|
||||||
pub use syntax::attr::InlineAttr;
|
pub use syntax::attr::InlineAttr;
|
||||||
|
@ -61,10 +63,8 @@ pub fn set_frame_pointer_elimination(ccx: &CrateContext, llfn: ValueRef) {
|
||||||
// parameter.
|
// parameter.
|
||||||
if ccx.sess().must_not_eliminate_frame_pointers() {
|
if ccx.sess().must_not_eliminate_frame_pointers() {
|
||||||
llvm::AddFunctionAttrStringValue(
|
llvm::AddFunctionAttrStringValue(
|
||||||
llfn,
|
llfn, llvm::AttributePlace::Function,
|
||||||
llvm::AttributePlace::Function,
|
cstr("no-frame-pointer-elim\0"), cstr("true\0"));
|
||||||
"no-frame-pointer-elim\0",
|
|
||||||
"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));
|
inline(llfn, find_inline_attr(Some(ccx.sess().diagnostic()), attrs));
|
||||||
|
|
||||||
set_frame_pointer_elimination(ccx, llfn);
|
set_frame_pointer_elimination(ccx, llfn);
|
||||||
|
let mut target_features = vec![];
|
||||||
for attr in attrs {
|
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);
|
Attribute::Cold.apply_llfn(Function, llfn);
|
||||||
} else if attr.check_name("naked") {
|
} else if attr.check_name("naked") {
|
||||||
naked(llfn, true);
|
naked(llfn, true);
|
||||||
|
@ -88,4 +96,14 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe
|
||||||
unwind(llfn, true);
|
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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,6 +316,9 @@ declare_features! (
|
||||||
|
|
||||||
// Allows `break {expr}` with a value inside `loop`s.
|
// Allows `break {expr}` with a value inside `loop`s.
|
||||||
(active, loop_break_value, "1.14.0", Some(37339)),
|
(active, loop_break_value, "1.14.0", Some(37339)),
|
||||||
|
|
||||||
|
// Allows #[target_feature(...)]
|
||||||
|
(active, target_feature, "1.15.0", None),
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_features! (
|
declare_features! (
|
||||||
|
@ -664,6 +667,10 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
|
||||||
"the `#[naked]` attribute \
|
"the `#[naked]` attribute \
|
||||||
is an experimental feature",
|
is an experimental feature",
|
||||||
cfg_fn!(naked_functions))),
|
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),
|
("export_name", Whitelisted, Ungated),
|
||||||
("inline", Whitelisted, Ungated),
|
("inline", Whitelisted, Ungated),
|
||||||
("link", Whitelisted, Ungated),
|
("link", Whitelisted, Ungated),
|
||||||
|
|
13
src/test/compile-fail/gated-target_feature.rs
Normal file
13
src/test/compile-fail/gated-target_feature.rs
Normal file
|
@ -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() {}
|
Loading…
Add table
Add a link
Reference in a new issue