]> git.lizzy.rs Git - rust.git/commitdiff
Add new #[target_feature = "..."] attribute.
authorAndrew Gallant <jamslam@gmail.com>
Wed, 30 Nov 2016 00:02:00 +0000 (19:02 -0500)
committerAndrew Gallant <jamslam@gmail.com>
Wed, 30 Nov 2016 01:32:14 +0000 (20:32 -0500)
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.

src/librustc_driver/target_features.rs
src/librustc_llvm/lib.rs
src/librustc_trans/attributes.rs
src/libsyntax/feature_gate.rs
src/test/compile-fail/gated-target_feature.rs [new file with mode: 0644]

index 876323d599e857bc3f30f867b3c07b36a84daab3..124e7aafcc5158b75b2fb4416f6f5a60d5199104 100644 (file)
@@ -24,7 +24,8 @@
 
 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.).
index c4ec418f224b579c00fad7ab0d755d06def05f57..5792ff7bd399b14d5c1f49af14ff59870944cfc7 100644 (file)
@@ -66,13 +66,13 @@ pub fn into_result(self) -> Result<(), ()> {
 
 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())
     }
 }
 
index f1e90419a49e2070508781b2f55821458598f295..efdd1b736f0e7ae77b8b14b69f1e5e89c53c414f 100644 (file)
@@ -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")
 }
index aa6a29b78b075d2263a5eb2ed194161f371db08e..9313a2681297eb4610555a38f62815d7720ed849 100644 (file)
@@ -316,6 +316,9 @@ pub fn new() -> 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 fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, Att
                                  "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),
diff --git a/src/test/compile-fail/gated-target_feature.rs b/src/test/compile-fail/gated-target_feature.rs
new file mode 100644 (file)
index 0000000..da2e41a
--- /dev/null
@@ -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() {}