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.).
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())
}
}
// 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;
// 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"));
}
}
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);
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")
}
// 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! (
"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),
--- /dev/null
+// 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() {}