Repository navigation
Add documentation for the target_feature attribute - #160218
valentynkit wants to merge 1 commit into
Conversation
|
I don't know too much about this attribute so I prefer letting someone else review it. r? @RalfJung |
|
|
|
The attribute is already documented in the Reference. Is it a good idea to duplicate that documentation here? |
There was a problem hiding this comment.
This seems correct from the opsem side but the writing needs work.
Unfortunately I don't have the time to shepherd this all the way through.
r? @workingjubilee
| // | ||
| /// Enables extra CPU instructions for a single function. | ||
| /// | ||
| /// A program is compiled for a baseline CPU, so instructions that only newer CPUs support go |
There was a problem hiding this comment.
Where does the baseline come from?
| /// baseline. The `-C target-feature` and `-C target-cpu` compiler flags enable features for the | ||
| /// whole crate instead, which raises the minimum CPU the binary runs on. |
There was a problem hiding this comment.
This is an oddly dangling remark without flow.
It seems better to first mention the -C flags, and then pivot from there to the per-function version. Also, -Ctarget-cpu is very different from -Ctarget-fature, so throwing them into one bag here is quite confusing. -Ctarget-feature and #[target_feature] are closely related, they work on the same set of features; that should be mentioned.
|
|
|
Also, given the context in #160219, I would like to emphasize that in my view, we should not land AI-generated docs. I don't know if these docs were AI-generated, and this is just my opinion as the official policy banning AI-generated docs has not landed yet. But to inform my own judgment as a reviewer I'd like to know whether you wrote these docs entirely yourself or whether you edited a draft that was generated by AI. This is relevant because AI-generated text and code needs to be reviewed in a very different way than human-written text and code (because the kinds of mistakes AIs make are different from the mistakes humans make). |
This comment has been minimized.
This comment has been minimized.
507f37d to
93b83d9
Compare
This comment has been minimized.
This comment has been minimized.
Thanks for reviewing and highlighting what worth attention. The initial version of this PR was AI-generated, and I hadn't disclosed that, sorry for that, I've changed how I work on contributions since getting the feedback on AI usage, and follow LLM Policy. As for the docs, I made it more guide focused, and beginner friendly, it's detailed so If you think anything should be cut out to not duplicate information from Reference, I could shrink it. |
|
Thanks for the update, I'll try to take a look soon. |
This comment has been minimized.
This comment has been minimized.
Document the built-in `target_feature` attribute, using the `#[doc(attribute = "..."`)]
93b83d9 to
a8ebb3a
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
☔ The latest upstream changes (presumably #164556) made this pull request unmergeable. Please resolve the merge conflicts by rebasing. |
Originally posted by @workingjubilee in #160218 (comment)
|
|
|
||
| #[doc(attribute = "target_feature")] | ||
| // | ||
| /// Enables extra CPU instructions for a single function. |
There was a problem hiding this comment.
Hmm. It's an ISA extension... it doesn't necessarily correspond exactly to extra instructions. The actual behavior is thus effectively to specify to the code generator that a behavior of the CPU is different (with the baseline being, yes, "more instructions are valid encodings instead of being undefined or only-trapping").
A good example of a non-instruction feature would be ermsb, AKA "rep movs is good": https://github.com/llvm/llvm-project/blob/4f7ca43759f63102f3f73677a5008d0a5576ed12/llvm/lib/Target/X86/X86.td#L398
It changes nothing about what the CPU can do, but encourages the compiler to use a simpler code pattern in some cases.
And yes, it is on the list of officially supported features:
$ rustc --print target-features
Features supported by rustc for this target:
...
ermsb - REP MOVS/STOS are fast.
Unfortunately crt-static is also a target feature, but I don't think we need to even think about it as IMO it should not have been. It is a far more annoying counterexample and it doesn't interact with a number of things "real" features do.
| /// Calling a `#[target_feature]` function on a CPU that lacks the features is undefined | ||
| /// behavior, unless the platform explicitly documents it to be safe. That is why the call | ||
| /// needs `unsafe`: the caller must verify that the features are present. Even in a crate built | ||
| /// with `-C target-feature=+avx2`, calling `increment_avx2` still needs `unsafe`; only a | ||
| /// caller that enables the same features through its own `#[target_feature]` attribute may | ||
| /// call it without. |
There was a problem hiding this comment.
Not "documents" here, but "defines". It needs to be a foundational promise. If it was okay today but may not be okay in the future, we couldn't rely on it, and vice versa, it needs to have been okay since the very start of the platform defined by the target. This is why wasm is allowed to be different, because invalid instructions must have a reliable behavior of being rejected, from the beginning of wasm onward.
Further, the feature doesn't need to just be physically available on the CPU. People must perform runtime detection instead of assuming a feature is enabled because e.g. the behavior is equally arbitrary if the OS refuses to enable the feature, from our perspective, though more typically it at least incurs an invalid instruction trap since the instruction does get parsed correctly.
...However, as noted by the Gracemont comment, this is not guaranteed, as a feature being disabled despite being physically available can be due to kernel software detecting a per-core ISA difference and thus refusing to enable it, and so using those instructions can still reach a hardware UB case even if some cores parse it correctly.
There was a problem hiding this comment.
I would invert this segment and start at the conclusion: Describe what is needed to be sound and correct, and then add the recursive exemption, and then add the wasm exemption (as that is the only platform that has such an exemption). Then -Ctarget-feature doesn't even come up because we are only describing what you must do. It's a red herring.
| /// The value of `enable` is one or more comma-separated feature names, and the names are | ||
| /// architecture-specific: `avx2` belongs to x86, `neon` to ARM. The `-C target-feature` flag |
There was a problem hiding this comment.
This feels vague to me between "each architecture has a set of names and those names are not assigned to other architectures" and "each name has a specific meaning for each architecture". It's the latter. They are not required to match to a single feature on a single architecture. Many platforms have aes, for example, which indicates the same computation but may have some variance in its implementation details. Also, we can have the same name mean fully different things based on architecture.
| /// Newer CPUs support instructions that older ones may lack. AVX2, for example, processes 32 | ||
| /// bytes in a single instruction, but a program using it everywhere cannot run on older machines. |
There was a problem hiding this comment.
Mmm. The CPUs that shipped with AVX2 were in 2011. They are quite old by now.
The difference is that Intel kept shipping new lines of non-AVX2 CPUs also until... oh, into the 2020s. Tremont misses AVX2. https://en.wikipedia.org/wiki/Tremont_(microarchitecture)
Gracemont has it, but missed AVX512, and that's why Alder Lake wound up not supporting AVX512 except for a few early CPUs that hadn't had it fused off yet. The motherboard is still supposed to disable their AVX512 though, so there's no per-core variance in instruction set.
There was a problem hiding this comment.
It would probably be better to say something like "early or low-power x86-64 CPUs", I think.
| /// needs `unsafe`: the caller must verify that the features are present. Even in a crate built | ||
| /// with `-C target-feature=+avx2`, calling `increment_avx2` still needs `unsafe`; only a | ||
| /// caller that enables the same features through its own `#[target_feature]` attribute may | ||
| /// call it without. |
There was a problem hiding this comment.
I believe this part is a fairly arbitrary decision by us so that whether a crate passes unsafety-checking doesn't depend on your specific -Ctarget-feature flags, it has less to do with soundness per se and more to do with making the compiler easy to wield.
| /// caller that enables the same features through its own `#[target_feature]` attribute may | ||
| /// call it without. | ||
| /// | ||
| /// The value of `enable` is one or more comma-separated feature names, and the names are |
There was a problem hiding this comment.
We should probably show what this looks like.
| /// The value of `enable` is one or more comma-separated feature names, and the names are | ||
| /// architecture-specific: `avx2` belongs to x86, `neon` to ARM. The `-C target-feature` flag | ||
| /// accepts the same names crate-wide, and run-time detection has per-architecture macros such | ||
| /// as [`is_x86_feature_detected`] and [`is_aarch64_feature_detected`], which callers use to | ||
| /// confirm the running CPU has a feature before the call. |
There was a problem hiding this comment.
It feels like this leaves slightly vague something that it should probably explicate: the same strings work for both.
In fact, we should probably move this way up, to near the start, and maybe reference rustc --print target-features?
|
Reminder, once the PR becomes ready for a review, use |

View all comments
Documents the
target_featureattribute, aiming at the guide level and beginner friendly. Low level details and per-architecture feature table stay out in the Reference.The example is wrapped in a hidden
#[cfg(target_arch = "x86_64")]block to make the example compile everywhere the doctests run.Part of #157604
r? @GuillaumeGomez
Tested with
./x test library/core --doc --test-args attribute_docsand the same forlibrary/std.