Skip to content

Commit 2cdbd5e

Browse files
committed
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.
2 parents 8900854 + 80ef1db commit 2cdbd5e

File tree

5 files changed

+50
-11
lines changed

5 files changed

+50
-11
lines changed

src/librustc_driver/target_features.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "vfp2\0", "vfp3\0", "
2424

2525
const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0",
2626
"sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0",
27-
"ssse3\0", "tbm\0"];
27+
"ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0",
28+
"sse4a\0"];
2829

2930
/// Add `target_feature = "..."` cfgs for a variety of platform
3031
/// specific features (SSE, NEON etc.).

src/librustc_llvm/lib.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@ impl LLVMRustResult {
6666

6767
pub fn AddFunctionAttrStringValue(llfn: ValueRef,
6868
idx: AttributePlace,
69-
attr: &'static str,
70-
value: &'static str) {
69+
attr: &CStr,
70+
value: &CStr) {
7171
unsafe {
7272
LLVMRustAddFunctionAttrStringValue(llfn,
7373
idx.as_uint(),
74-
attr.as_ptr() as *const _,
75-
value.as_ptr() as *const _)
74+
attr.as_ptr(),
75+
value.as_ptr())
7676
}
7777
}
7878

src/librustc_trans/attributes.rs

+24-6
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
// except according to those terms.
1010
//! Set and unset common attributes on LLVM values.
1111
12+
use std::ffi::{CStr, CString};
13+
1214
use llvm::{self, Attribute, ValueRef};
1315
use llvm::AttributePlace::Function;
1416
pub use syntax::attr::InlineAttr;
@@ -61,10 +63,8 @@ pub fn set_frame_pointer_elimination(ccx: &CrateContext, llfn: ValueRef) {
6163
// parameter.
6264
if ccx.sess().must_not_eliminate_frame_pointers() {
6365
llvm::AddFunctionAttrStringValue(
64-
llfn,
65-
llvm::AttributePlace::Function,
66-
"no-frame-pointer-elim\0",
67-
"true\0")
66+
llfn, llvm::AttributePlace::Function,
67+
cstr("no-frame-pointer-elim\0"), cstr("true\0"));
6868
}
6969
}
7070

@@ -75,9 +75,17 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe
7575
inline(llfn, find_inline_attr(Some(ccx.sess().diagnostic()), attrs));
7676

7777
set_frame_pointer_elimination(ccx, llfn);
78-
78+
let mut target_features = vec![];
7979
for attr in attrs {
80-
if attr.check_name("cold") {
80+
if attr.check_name("target_feature") {
81+
if let Some(val) = attr.value_str() {
82+
for feat in val.as_str().split(",").map(|f| f.trim()) {
83+
if !feat.is_empty() && !feat.contains('\0') {
84+
target_features.push(feat.to_string());
85+
}
86+
}
87+
}
88+
} else if attr.check_name("cold") {
8189
Attribute::Cold.apply_llfn(Function, llfn);
8290
} else if attr.check_name("naked") {
8391
naked(llfn, true);
@@ -88,4 +96,14 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe
8896
unwind(llfn, true);
8997
}
9098
}
99+
if !target_features.is_empty() {
100+
let val = CString::new(target_features.join(",")).unwrap();
101+
llvm::AddFunctionAttrStringValue(
102+
llfn, llvm::AttributePlace::Function,
103+
cstr("target-features\0"), &val);
104+
}
105+
}
106+
107+
fn cstr(s: &'static str) -> &CStr {
108+
CStr::from_bytes_with_nul(s.as_bytes()).expect("null-terminated string")
91109
}

src/libsyntax/feature_gate.rs

+7
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,9 @@ declare_features! (
316316

317317
// Allows `break {expr}` with a value inside `loop`s.
318318
(active, loop_break_value, "1.14.0", Some(37339)),
319+
320+
// Allows #[target_feature(...)]
321+
(active, target_feature, "1.15.0", None),
319322
);
320323

321324
declare_features! (
@@ -664,6 +667,10 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
664667
"the `#[naked]` attribute \
665668
is an experimental feature",
666669
cfg_fn!(naked_functions))),
670+
("target_feature", Whitelisted, Gated(
671+
Stability::Unstable, "target_feature",
672+
"the `#[target_feature]` attribute is an experimental feature",
673+
cfg_fn!(target_feature))),
667674
("export_name", Whitelisted, Ungated),
668675
("inline", Whitelisted, Ungated),
669676
("link", Whitelisted, Ungated),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[target_feature = "+sse2"]
12+
//~^ the `#[target_feature]` attribute is an experimental feature
13+
fn foo() {}

0 commit comments

Comments
 (0)