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. This commit also expands the target feature whitelist to include lzcnt, popcnt and sse4a. Namely, lzcnt and popcnt have their own CPUID bits, but were introduced with SSE4.
This commit is contained in:
parent
5de15be5ec
commit
80ef1dbf2d
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