Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new #[target_feature = "..."] attribute. #38079

Merged
merged 1 commit into from Dec 3, 2016

Conversation

Projects
None yet
9 participants
@BurntSushi
Copy link
Member

BurntSushi commented Nov 30, 2016

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.

@rust-highfive

This comment has been minimized.

Copy link
Collaborator

rust-highfive commented Nov 30, 2016

r? @pnkfelix

(rust_highfive has picked a reviewer for you, use r? to override)

@BurntSushi

This comment has been minimized.

Copy link
Member Author

BurntSushi commented Nov 30, 2016

@BurntSushi

This comment has been minimized.

Copy link
Member Author

BurntSushi commented Nov 30, 2016

Here are some questions/comments/concerns:

  1. There is no validation of the values in target_feature. They are passed directly to LLVM at codegen time. This means errors (if any) are reported at codegen time.
  2. The only test here is a compile-fail test that checks that target_feature is gated. I wanted to write a codegen test, but I don't quite know how for this particular change.
  3. Should it be unsafe to call a function decorated with the target_feature attribute? (A different phrasing: should application of target_feature be limited to unsafe functions?)

I don't know whether any of the above should be fixed before merging. Certainly, they should at least be fixed/addressed before stabilization.

@BurntSushi

This comment has been minimized.

Copy link
Member Author

BurntSushi commented Nov 30, 2016

cc @eddyb

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Nov 30, 2016

@@ -60,11 +62,10 @@ pub fn set_frame_pointer_elimination(ccx: &CrateContext, llfn: ValueRef) {
// FIXME: #11906: Omitting frame pointers breaks retrieving the value of a
// parameter.
if ccx.sess().must_not_eliminate_frame_pointers() {
let name = CString::new("no-frame-pointer-elim").unwrap();
let val = CString::new("true").unwrap();

This comment has been minimized.

@eddyb

eddyb Nov 30, 2016

Member

I think you can still use CStr with null-terminated &str.

for attr in attrs {
if attr.check_name("cold") {
if attr.check_name("target_feature") {
let val = attr.value_str().map_or(String::new(), |s|s.to_string());

This comment has been minimized.

@eddyb

eddyb Nov 30, 2016

Member

This shouldn't allocate. You can use let val = attr.value_str().map(|s| s.as_str()); ... val.map_or("", |s| &s[..]).split(",").

This comment has been minimized.

@BurntSushi

BurntSushi Nov 30, 2016

Author Member

It turns out this doesn't work because s is an InternedString. I just took the hit with the extra case analysis instead.

for feat in val.split(",") {
let feat = feat.trim().to_string();
if !feat.is_empty() && !feat.contains('\0') {
target_features.push(feat);

This comment has been minimized.

@eddyb

eddyb Nov 30, 2016

Member

You can move the .to_string() on this line, or push to a String instead of allocating for each one.

@@ -88,4 +97,10 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe
unwind(llfn, true);
}
}
if !target_features.is_empty() {
let name = CString::new("target-features").unwrap();

This comment has been minimized.

@eddyb

eddyb Nov 30, 2016

Member

Same here, I'm pretty sure you could avoid the allocation.

This comment has been minimized.

@BurntSushi

BurntSushi Nov 30, 2016

Author Member

Yeah, I just didn't really care about the allocation. I'll fix them. :-)

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Nov 30, 2016

The x86 whitelist has ramifications elsewhere for the stable name of these features. The intention is that we ourselves maintain a mapping of features to the actual LLVM names, so that way if LLVM changes a name we can just update our implementation but the name we present to Rust is always stable.

In that sense could we perhaps be more conservative with the update to the x86 whitelist? Perhaps only the features needed for SIMD progress for now?

@BurntSushi

This comment has been minimized.

Copy link
Member Author

BurntSushi commented Nov 30, 2016

@alexcrichton Ah whoops! I will trim it back down to what it was, but I think we should add at least lzcnt, popcnt and sse4a. lzcnt and popcnt in particular were introduced with SSE4, but they were given their own CPUID bits. See: https://en.wikipedia.org/wiki/SSE4#POPCNT_and_LZCNT

@BurntSushi

This comment has been minimized.

Copy link
Member Author

BurntSushi commented Nov 30, 2016

(We will definitely want to add more from that list at time moves on. AVX512 has a particularly large presence, but I think we should punt on AVX512 for this initial push. It it absolutely gigantic.)

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.

@BurntSushi BurntSushi force-pushed the BurntSushi:attrtarget branch from e46652a to 80ef1db Nov 30, 2016

@sfackler

This comment has been minimized.

Copy link
Member

sfackler commented Nov 30, 2016

I think I'd agree that we should require target_feature functions to be unsafe.

EDIT: Hmm, maybe not - I don't think you'd see anything worse than a crash, and a crash isn't memory unsafe, right?

@BurntSushi

This comment has been minimized.

Copy link
Member Author

BurntSushi commented Nov 30, 2016

To be more precise, I think the failure mode is that your program attempts to execute an instruction that the CPU doesn't recognize. Is this behavior actually defined to always crash your program?

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Nov 30, 2016

@BurntSushi If the kernel doesn't emulate it then you get a SIGILL on most UNIX systems (I would hope).
Paging @retep998 for windows behavior (I'd assume it's a SEH exception or something similar).

@retep998

This comment has been minimized.

Copy link
Member

retep998 commented Nov 30, 2016

If you attempt to execute an illegal instruction on Windows, a STATUS_ILLEGAL_INSTRUCTION exception is fired.

@sanxiyn

This comment has been minimized.

Copy link
Member

sanxiyn commented Nov 30, 2016

Note that "target-features" function attribute is undocumented. So while LLVM is unstable, this attribute is extra unstable, even unstable by LLVM standard.

At least in 2015, a bug about "target-features" function attribute was closed as "LATER". See LLVM bug 22081. Hopefully this changed, but I haven't seen any announcement. Did anyone?

@BurntSushi

This comment has been minimized.

Copy link
Member Author

BurntSushi commented Nov 30, 2016

@sanxiyn If it's good enough for Clang and LDC, is it good enough for Rust? (I note that gcc seems to support a similar---possibly identical---feature.)

As a side note, our current trajectory for SIMD stabilization hinges pretty critically on #[target_feature]. Without it, we're pretty much back to the drawing board. (One possibility would be to keep the attribute unstable and only use it in std, which would get us somewhere, but that seems unfortunate.)

I don't know what the proper channels are to inquire about something like this.

@sanxiyn

This comment has been minimized.

Copy link
Member

sanxiyn commented Nov 30, 2016

I am simply pointing out two things. One, the attribute is unstable in LLVM. Of course, that doesn't mean it can't be stable in Rust. In principle, Rust is already using LLVM C++ API, which is also unstable.

Two, #[target_feature] and -C target-feature are not equivalent. They should be, but for various reasons they aren't at the moment. And as far as I know LLVM upstream is not very interested in fixing cases when they aren't equivalent.

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Dec 1, 2016

r+ from me on this. I'm fine on punting on requiring unsafe. This is an unstable feature for now and we'll spec it out more before stabilizing. In the time being it allows playing around with SIMD and exploring the possible design space there.

I'm also fine using something unstable in LLVM, especially in an unstable API. Presumably the clang feature of __attribute__ is "stable", so there will always be some way of doing this. If that changes over time in LLVM revisions then it's no different than anything else we use from LLVM, really.

@eddyb do all the trans pieces here look good to you?

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Dec 1, 2016

Yeah, it looks good to me.

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Dec 1, 2016

Ok

@bors: r+

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Dec 1, 2016

📌 Commit 80ef1db has been approved by alexcrichton

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Dec 3, 2016

⌛️ Testing commit 80ef1db with merge 2cdbd5e...

bors added a commit that referenced this pull request Dec 3, 2016

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.

@bors bors merged commit 80ef1db into rust-lang:master Dec 3, 2016

2 checks passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
homu Test successful
Details

@bors bors referenced this pull request Dec 3, 2016

Closed

i128 and u128 support #37900

2 of 2 tasks complete

@BurntSushi BurntSushi deleted the BurntSushi:attrtarget branch Dec 3, 2016

@bors bors referenced this pull request Dec 3, 2016

Merged

Cast suggestions #38099

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.