Skip to content

Conversation

@a4lg
Copy link
Contributor

@a4lg a4lg commented Aug 24, 2025

This PR implements new feature to std_detect's feature! macro: implication of target features by custom cfg and then uses this to implement static implication logic on RISC-V where the standard target feature handling does not capture all the cases.

This PR implements implication logic for three kinds of target features:

  1. Group extensions where each equals aggregation of its sub-extensions (exact)
  2. Complex implications around the "C" extension (in a best effort manner)

For detailed intent of the changes, see each commit message.

It also changes some AArch64 code to use the new syntax added in this PR and removes the old custom syntax to imply a target feature.

cf. Z3-based prover for complex implications around the "C" extension

Draft Design Consideration 1: RISC-V: How to handle ISA Bases?

Implementing custom implications to base ISA target features like rv32i might be an option but I have a concern (which will not happen for now but plausible in the future).

In particular, I have a concern on the following case: the program is built for an rv32e target but ran on an rv32i environment (which is a superset of rv32e) and reports existence of rv32i. If that happens, both rv32e and rv32i would return true on std::arch::is_riscv_feature_detected!.

So, the commit implementing implication of base ISA target features (originally commit 3) was marked DRAFT.

My original position: Slightly Negative.

Conclusion: Remove original commit 3 and do not imply ISA bases.

Draft Design Consideration 2: Substituting implied by target_features:

This PR (originally commit 2) implements implication by custom cfg with following syntax: implied by cfg(CFG);.
Unlike existing implied by target_features: [A, B, ...]; (which will work like cfg(any(target_feature = "A", target_feature = "B", ...))), this syntax accepts any cfgs.

Interestingly, implied by target_features: is currently only used on AArch64 and in the simplest form (implied from one target feature). So if there's no good reason keeping this, we have an option to remove implied by target_features: [...]; entirely and substitute with implied by cfg(...);.

Commits that make such changes (originally commits 6 and 7) were marked DRAFT.

My original position: Positive (but leaving draft after hearing from others).

Conclusion: Substitute as the original.

r? @Amanieu
@rustbot label +O-riscv

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-libs Relevant to the library team, which will review and decide on the PR/issue. O-riscv Target: RISC-V architecture labels Aug 24, 2025
@Amanieu
Copy link
Member

Amanieu commented Aug 29, 2025

RFC 1: RISC-V: How to handle ISA Bases?

RV32E specifically implies an RV32E environment and RV32E calling conventions. The e feature should never be reported as enabled in an RV32I environment.

RFC 2: Substituting implied by target_features:

This seems fine.

@a4lg
Copy link
Contributor Author

a4lg commented Aug 30, 2025

@Amanieu Thanks!
Okay, your opinion almost matches to my position and happy to agree with it (I'll remove ISA base implication).

I'll make a few adjustments and make this PR to leave the draft state.

a4lg added 6 commits August 30, 2025 03:36
Internal calls to `$crate::detect_feature!` and `check_cfg_feature!` are
long enough and we are going to add another option.

This commit formats internal macro invocation for the future.
It also reformats the contents of `check_cfg_feature!` to comply with
`./x fmt check` (raises an error after modification of subsequent commits).
This commit adds an option to `@FEATURE` specification of the
`feature!` macro: `implied by cfg(CUSTOM_CFG);`.

It enables implying a target feature by custom configuration such like
`all(target_feature = "A", target_feature = "B")`, which was impossible
before this commit.

The main reason adding this option is to properly support RISC-V "group"
extensions (e.g. "A", which consists of "Zalrsc" and "Zaamo" subextensions)
and other extensions with complex implications (like "Zcd", can be implied
if both "C" and "D" are enabled but not vice versa).

With this commit, we can make `is_riscv_feature_detected!` macro to
properly detect existence of certain target features supplied via compiler
options (sometimes exactly, on other times in a best-effort manner).
RISC-V has a sort of "group" extensions.  For example, the "A" extension
consists of two subextensions "Zalrsc" and "Zaamo" and having two
subextensions is equivalent to having the "A" extension (group).

This commit implements implication of such target features exactly.

For "group" extensions (except "C"), implication logic looks like:

```
cfg(any(
    target_feature = "group",
    all(
        target_feature = "feat1",
        target_feature = "feat2",
        target_feature = "feat3",
        // ...
    )
))
```

...where each `featN` is a non-group subextension and supporting
all `featN` is equivalent to the support of the entire group.

Testing `target_feature = "group"` is technically redundant on user programs
but kept here to test `cfg`s while compiling the standard library and
evaluation cost at compile-time should not be large.
On the RISC-V architecture, there are some complex implications around the
"C" extension.  This commit implements implication of such target features
in a best effort manner.

The reason why we cannot make this exact is lack of `"zcd"` and `"zcf"`
target features (that would require additional feature handling system).

Still, weaker implications implemented here are formally verified to be
optimal if we have to avoid tautology (except `"c"`) and uses of `"zcf"`
and `"zcd"` are prohibited.

For "C", the author deduced minimal expression which makes equal to the
"C" extension and extracted all cases where `"zcd"` and `"zcf"` are not
involved.

For "Zcd" and "Zcf", the author created proof statements, each stating
that implication expression (which avoids tautology and accidentally
avoids using `"zcd"` or `"zcf"`) is optimal to force corresponding
target feature to be enabled.
`implied by target_features: [...]` is currently only used on
the AArch64 architecture.

Since those uses can be substituted with
`implied by cfg(any(target_feature = ...))` or more simply
`implied by cfg(target_feature = ...)` (if there's only 1 target feature
to imply from), this commit attempts to use this for simplicity.
This commit removes `implied by target_features: [...];` inside
the target description macro `features!` (which is superseded by the
`implied by cfg(...);` syntax).
@a4lg a4lg force-pushed the std-detect-complex-implication branch from a05d4bd to 99d68f3 Compare August 30, 2025 03:42
@a4lg a4lg marked this pull request as ready for review August 30, 2025 03:44
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 30, 2025
/// "Zvkn" Cryptography Extension for NIST Algorithm Suite
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvknc: "zvknc";
implied by cfg(any(
target_feature = "zvknc",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line seems redundant and could be folded into the macro itself: a feature is always implied by itself.

Copy link
Contributor Author

@a4lg a4lg Sep 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... unless implied by is used (even implied by target_features:, which is to be removed in this PR suppresses self implication; see the macro expansion carefully).
So, zvknc runtime (std_detect) target feature is not directly implied by zvknc compiler target feature itself.

Still, you are technically right since... for instance (in this place), zvknc is just a collection of sub-extensions (zvkned, zvknhb...) and zvknc compiler target feature directly/indirectly enables all of them (indirectly enabling runtime target feature zvknc).
The reason I keep zvknc itself is to check validity of the compiler target feature (through check_cfg_feature!).

I think we can keep this (and similar lines) as-is (in this PR).

@Amanieu
Copy link
Member

Amanieu commented Oct 12, 2025

I've been thinking about this PR a bit and I think that the best place for all the feature implication logic is actually in rustc itself rather than here. This will ensure that feature checking with cfg(target_feature) also properly reflects the features enabled via the command-line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

O-riscv Target: RISC-V architecture S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants