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
@ -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.).
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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),
|
||||
|
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…
Reference in New Issue
Block a user