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

ARM target-feature cfgs are not enabled when the target-feature is enabled #83975

Closed
mattico opened this issue Apr 7, 2021 · 3 comments
Closed
Labels
C-bug Category: This is a bug.

Comments

@mattico
Copy link
Contributor

mattico commented Apr 7, 2021

$ rustc --version
rustc 1.53.0-nightly (07e0e2ec2 2021-03-24)
$ rustc --target=thumbv7em-none-eabihf --print cfg
<snip>
target_feature="dsp"
target_feature="mclass"
target_feature="thumb-mode"
target_feature="v5te"
target_feature="v6"
target_feature="v6k"
target_feature="v6t2"
target_feature="v7"
<snip>
$ rustc --target=thumbv7em-none-eabihf -C target-feature=+armv7e-m,+m7,+v7clrex,+fp-armv8d16,+hwdiv,+fp64,+fpregs,+fpregs64,+noarm,+db,+thumb2 --print cfg
<snip>
target_feature="dsp"
target_feature="mclass"
target_feature="thumb-mode"
target_feature="v5te"
target_feature="v6"
target_feature="v6k"
target_feature="v6t2"
target_feature="v7"
target_feature="vfp2"
<snip>

To the best of my knowledge, all of the above features are valid for my target, an STM32H743XIH6. At the very least fp-armv8d16 is valid for Cortex-M7 targets: fpv5 has the same instructions as ARMv8. If any of the target features are not valid, rustc should print a warning message.

However, rustc doesn't appear to actually enable any of the target_feature cfgs, somehow deciding that vfp2 is good enough - despite the fact that vfp2 isn't even a valid option for ARMv7e-M1. Testing the enabled features using cfg! or #[cfg()] gives the same result (I wish I had found --print cfg sooner).

I did some comparisons using godbolt: Rust | C GCC/Clang
It appears that the target-features are working, at least the ones that I can easily generate instructions for. Enabling any feature which tells LLVM there's 64-bit float support causes it to emit all 64-bit float instructions. Disabling v7clrex causes it to stop emitting clrex.

I think what's happening is there's some logic in LLVM which enables other target features and internal flags based on the target features it's given. Then it/rustc finds a minimum set of target-features which would end up enabling the resulting internal flags - e.g. vfp2 enables fp64 so since fp64 is enabled we'll say that vfp2 is enabled. Then that reduced set of features is what actually ends up as cfgs. This makes #[cfg(target_feature = "")] almost useless on ARM since most of the target-features say they are disabled even when they seem to work.

Footnotes

  1. Armv7-M Architecture Reference Manual section A2.5

@mattico mattico added the C-bug Category: This is a bug. label Apr 7, 2021
@mattico
Copy link
Contributor Author

mattico commented Apr 7, 2021

This seems relevant:

const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("aclass", Some(sym::arm_target_feature)),
("mclass", Some(sym::arm_target_feature)),
("rclass", Some(sym::arm_target_feature)),
("dsp", Some(sym::arm_target_feature)),
("neon", Some(sym::arm_target_feature)),
("crc", Some(sym::arm_target_feature)),
("crypto", Some(sym::arm_target_feature)),
("v5te", Some(sym::arm_target_feature)),
("v6", Some(sym::arm_target_feature)),
("v6k", Some(sym::arm_target_feature)),
("v6t2", Some(sym::arm_target_feature)),
("v7", Some(sym::arm_target_feature)),
("v8", Some(sym::arm_target_feature)),
("vfp2", Some(sym::arm_target_feature)),
("vfp3", Some(sym::arm_target_feature)),
("vfp4", Some(sym::arm_target_feature)),
// This is needed for inline assembly, but shouldn't be stabilized as-is
// since it should be enabled per-function using #[instruction_set], not
// #[target_feature].
("thumb-mode", Some(sym::arm_target_feature)),
];
const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("fp", Some(sym::aarch64_target_feature)),
("neon", Some(sym::aarch64_target_feature)),
("sve", Some(sym::aarch64_target_feature)),
("crc", Some(sym::aarch64_target_feature)),
("crypto", Some(sym::aarch64_target_feature)),
("ras", Some(sym::aarch64_target_feature)),
("lse", Some(sym::aarch64_target_feature)),
("rdm", Some(sym::aarch64_target_feature)),
("fp16", Some(sym::aarch64_target_feature)),
("rcpc", Some(sym::aarch64_target_feature)),
("dotprod", Some(sym::aarch64_target_feature)),
("tme", Some(sym::aarch64_target_feature)),
("v8.1a", Some(sym::aarch64_target_feature)),
("v8.2a", Some(sym::aarch64_target_feature)),
("v8.3a", Some(sym::aarch64_target_feature)),
];

I didn't know that cfg_target_feature isn't stabilized yet, which is easy to miss since I didn't need to enable any unstable features. That list of supported features seems to line up with the cfgs which are actually enabled. One remaining question is why vfp4 isn't enabled when that's supposedly supported.

@mattico
Copy link
Contributor Author

mattico commented Apr 7, 2021

LLVM has ArmTargetParser::getFpuSynonym which converts vfp4 to vfpv4, but it might not be used consistently. Some places in LLVM use vfp4 and some use vfpv4.

Also, despite the thumbv7em-none-eabihf target already having +vfp4, if you then manually enable it again it actually works:

rustc +nightly --target thumbv7em-none-eabihf -Ctarget-feature=+vfp4 --print cfg
debug_assertions
panic="abort"
target_arch="arm"
target_endian="little"
target_env=""
target_feature="dsp"
target_feature="mclass"
target_feature="thumb-mode"
target_feature="v5te"
target_feature="v6"
target_feature="v6k"
target_feature="v6t2"
target_feature="v7"
target_feature="vfp2"
target_feature="vfp3"
target_feature="vfp4"

@mattico
Copy link
Contributor Author

mattico commented Apr 7, 2021

So the target_features allowed in cfg are (I think deliberately) limited to a specific whitelist which is also used for #[target_feature], though this isn't documented anywhere that I can find. So that resolves the original issue. I'm going to close this and create new issues for the more specific issues that were identified.

@mattico mattico closed this as completed Apr 7, 2021
bors added a commit to rust-lang-ci/rust that referenced this issue Apr 9, 2021
…ments, r=petrochenkov

Categorize and explain target features support

There are 3 different uses of the `-C target-feature` args passed to rustc:
1. All of the features are passed to LLVM, which uses them to configure code-generation. This is sort-of stabilized since 1.0 though LLVM does change/add/remove target features regularly.
2. Target features which are in [the compiler's allowlist](https://github.com/rust-lang/rust/blob/69e1d22ddbc67b25141a735a22a8895a678b32ca/compiler/rustc_codegen_ssa/src/target_features.rs#L12-L34) can be used in `cfg!(target_feature)` etc. These may have different names than in LLVM and are renamed before passing them to LLVM.
3. Target features which are in the allowlist and which are stabilized or feature-gate-enabled can be used in `#[target_feature]`.

It can be confusing that `rustc --print target-features` just prints out the LLVM features without separating out the rustc features or even mentioning that the dichotomy exists.

This improves the situation by separating out the rustc and LLVM target features and adding a brief explanation about the difference.

Abbreviated Example Output:
```
$ rustc --print target-features
Features supported by rustc for this target:
    adx                         - Support ADX instructions.
    aes                         - Enable AES instructions.
...
    xsaves                      - Support xsaves instructions.
    crt-static                  - Enables libraries with C Run-time Libraries(CRT) to be statically linked.

Code-generation features supported by LLVM for this target:
    16bit-mode                  - 16-bit mode (i8086).
    32bit-mode                  - 32-bit mode (80386).
...
    x87                         - Enable X87 float instructions.
    xop                         - Enable XOP instructions.

Use +feature to enable a feature, or -feature to disable it.
For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2

Code-generation features cannot be used in cfg or #[target_feature],
and may be renamed or removed in a future version of LLVM or rustc.

```

Motivated by rust-lang#83975.
CC rust-lang#49653
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

1 participant