From 55a08bc922d3dd801ef1772eefc2d475b9fc00b0 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sun, 24 Aug 2025 08:34:14 +0000 Subject: [PATCH 1/6] std_detect: Tidying for preparation of adding `@FEATURE` options 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). --- library/std_detect/src/detect/macros.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/library/std_detect/src/detect/macros.rs b/library/std_detect/src/detect/macros.rs index 17140e15653d2..33f1a792acd76 100644 --- a/library/std_detect/src/detect/macros.rs +++ b/library/std_detect/src/detect/macros.rs @@ -24,7 +24,9 @@ macro_rules! check_cfg_feature { }; ($feature:tt, $feature_lit:tt, without cfg check: $feature_cfg_check:literal) => { #[allow(unexpected_cfgs, reason = $feature_lit)] - { cfg!(target_feature = $feature_lit) } + { + cfg!(target_feature = $feature_lit) + } }; } @@ -50,7 +52,12 @@ macro_rules! features { macro_rules! $macro_name { $( ($feature_lit) => { - $crate::detect_feature!($feature, $feature_lit $(, without cfg check: $feature_cfg_check)? $(: $($target_feature_lit),*)?) + $crate::detect_feature!( + $feature, + $feature_lit + $(, without cfg check: $feature_cfg_check)? + $(: $($target_feature_lit),*)? + ) }; )* $( @@ -135,7 +142,12 @@ macro_rules! features { #[deny(unfulfilled_lint_expectations)] const _: () = { $( - check_cfg_feature!($feature, $feature_lit $(, without cfg check: $feature_cfg_check)? $(: $($target_feature_lit),*)?); + check_cfg_feature!( + $feature, + $feature_lit + $(, without cfg check: $feature_cfg_check)? + $(: $($target_feature_lit),*)? + ); )* }; From 09dc987c30c542ceabc5d635083dd27e65bbfa9b Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sun, 24 Aug 2025 08:34:15 +0000 Subject: [PATCH 2/6] std_detect: Add implication from custom `cfg` 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). --- library/std_detect/src/detect/macros.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/std_detect/src/detect/macros.rs b/library/std_detect/src/detect/macros.rs index 33f1a792acd76..0bdd72cbf4fda 100644 --- a/library/std_detect/src/detect/macros.rs +++ b/library/std_detect/src/detect/macros.rs @@ -9,6 +9,9 @@ macro_rules! detect_feature { $(cfg!(target_feature = $target_feature_lit) ||)* $crate::detect::__is_feature_detected::$feature() }; + ($feature:tt, $feature_lit:tt : cfg($target_feature_cfg:meta)) => { + cfg!($target_feature_cfg) || $crate::detect::__is_feature_detected::$feature() + }; ($feature:tt, $feature_lit:tt, without cfg check: true) => { $crate::detect::__is_feature_detected::$feature() }; @@ -22,6 +25,9 @@ macro_rules! check_cfg_feature { ($feature:tt, $feature_lit:tt : $($target_feature_lit:tt),*) => { $(cfg!(target_feature = $target_feature_lit);)* }; + ($feature:tt, $feature_lit:tt : cfg($target_feature_cfg:meta)) => { + cfg!($target_feature_cfg); + }; ($feature:tt, $feature_lit:tt, without cfg check: $feature_cfg_check:literal) => { #[allow(unexpected_cfgs, reason = $feature_lit)] { @@ -42,6 +48,7 @@ macro_rules! features { $(@FEATURE: #[$stability_attr:meta] $feature:ident: $feature_lit:tt; $(without cfg check: $feature_cfg_check:tt;)? $(implied by target_features: [$($target_feature_lit:tt),*];)? + $(implied by cfg($target_feature_cfg:meta);)? $(#[$feature_comment:meta])*)* ) => { #[macro_export] @@ -57,6 +64,7 @@ macro_rules! features { $feature_lit $(, without cfg check: $feature_cfg_check)? $(: $($target_feature_lit),*)? + $(: cfg($target_feature_cfg))? ) }; )* @@ -147,6 +155,7 @@ macro_rules! features { $feature_lit $(, without cfg check: $feature_cfg_check)? $(: $($target_feature_lit),*)? + $(: cfg($target_feature_cfg))? ); )* }; From f4e980882f5bef98ac26d8b5c49cb72f71494e26 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sun, 24 Aug 2025 08:34:15 +0000 Subject: [PATCH 3/6] std_detect: RISC-V: Best effort implication by target config (group) 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. --- library/std_detect/src/detect/arch/riscv.rs | 107 ++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/library/std_detect/src/detect/arch/riscv.rs b/library/std_detect/src/detect/arch/riscv.rs index 1e57d09edb143..72c28a655accc 100644 --- a/library/std_detect/src/detect/arch/riscv.rs +++ b/library/std_detect/src/detect/arch/riscv.rs @@ -220,6 +220,13 @@ features! { /// "M" Extension for Integer Multiplication and Division @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] a: "a"; + implied by cfg(any( + target_feature = "a", + all( + target_feature = "zalrsc", + target_feature = "zaamo", + ) + )); /// "A" Extension for Atomic Instructions @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zalrsc: "zalrsc"; /// "Zalrsc" Extension for Load-Reserved/Store-Conditional Instructions @@ -278,6 +285,14 @@ features! { /// "Zcmop" Extension for Compressed May-Be-Operations @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] b: "b"; + implied by cfg(any( + target_feature = "b", + all( + target_feature = "zba", + target_feature = "zbb", + target_feature = "zbs", + ) + )); /// "B" Extension for Bit Manipulation @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zba: "zba"; /// "Zba" Extension for Address Generation @@ -307,10 +322,44 @@ features! { @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zkr: "zkr"; /// "Zkr" Entropy Source Extension @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zkn: "zkn"; + implied by cfg(any( + target_feature = "zkn", + all( + target_feature = "zbkb", + target_feature = "zbkc", + target_feature = "zbkx", + target_feature = "zkne", + target_feature = "zknd", + target_feature = "zknh", + ) + )); /// "Zkn" Cryptography Extension for NIST Algorithm Suite @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zks: "zks"; + implied by cfg(any( + target_feature = "zks", + all( + target_feature = "zbkb", + target_feature = "zbkc", + target_feature = "zbkx", + target_feature = "zksed", + target_feature = "zksh", + ) + )); /// "Zks" Cryptography Extension for ShangMi Algorithm Suite @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zk: "zk"; + implied by cfg(any( + target_feature = "zk", + all( + target_feature = "zbkb", + target_feature = "zbkc", + target_feature = "zbkx", + target_feature = "zkne", + target_feature = "zknd", + target_feature = "zknh", + target_feature = "zkr", + target_feature = "zkt", + ) + )); /// "Zk" Cryptography Extension for Standard Scalar Cryptography @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zkt: "zkt"; /// "Zkt" Cryptography Extension for Data Independent Execution Latency @@ -355,16 +404,74 @@ features! { @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksh: "zvksh"; /// "Zvksh" Cryptography Extension for ShangMi Suite: Vector SM3 Secure Hash @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkn: "zvkn"; + implied by cfg(any( + target_feature = "zvkn", + all( + target_feature = "zvkned", + target_feature = "zvknhb", + target_feature = "zvkb", + target_feature = "zvkt", + ) + )); /// "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", + all( + target_feature = "zvkned", + target_feature = "zvknhb", + target_feature = "zvkb", + target_feature = "zvkt", + target_feature = "zvbc", + ) + )); /// "Zvknc" Cryptography Extension for NIST Algorithm Suite with Carryless Multiply @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkng: "zvkng"; + implied by cfg(any( + target_feature = "zvkng", + all( + target_feature = "zvkned", + target_feature = "zvknhb", + target_feature = "zvkb", + target_feature = "zvkt", + target_feature = "zvkg", + ) + )); /// "Zvkng" Cryptography Extension for NIST Algorithm Suite with GCM @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvks: "zvks"; + implied by cfg(any( + target_feature = "zvks", + all( + target_feature = "zvksed", + target_feature = "zvksh", + target_feature = "zvkb", + target_feature = "zvkt", + ) + )); /// "Zvks" Cryptography Extension for ShangMi Algorithm Suite @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksc: "zvksc"; + implied by cfg(any( + target_feature = "zvksc", + all( + target_feature = "zvksed", + target_feature = "zvksh", + target_feature = "zvkb", + target_feature = "zvkt", + target_feature = "zvbc", + ) + )); /// "Zvksc" Cryptography Extension for ShangMi Algorithm Suite with Carryless Multiply @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksg: "zvksg"; + implied by cfg(any( + target_feature = "zvksg", + all( + target_feature = "zvksed", + target_feature = "zvksh", + target_feature = "zvkb", + target_feature = "zvkt", + target_feature = "zvkg", + ) + )); /// "Zvksg" Cryptography Extension for ShangMi Algorithm Suite with GCM @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkt: "zvkt"; /// "Zvkt" Extension for Vector Data-Independent Execution Latency From 61c6b10a9222115315cd014ca6ee2f1a034b1238 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sun, 24 Aug 2025 08:34:15 +0000 Subject: [PATCH 4/6] std_detect: RISC-V: Best effort implication by target config (C-related) 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. --- library/std_detect/src/detect/arch/riscv.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/library/std_detect/src/detect/arch/riscv.rs b/library/std_detect/src/detect/arch/riscv.rs index 72c28a655accc..2f2975450535f 100644 --- a/library/std_detect/src/detect/arch/riscv.rs +++ b/library/std_detect/src/detect/arch/riscv.rs @@ -270,14 +270,22 @@ features! { /// "Zhinxmin" Extension for Minimal Half-Precision Floating-Point in Integer Registers @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] c: "c"; + implied by cfg(any( + target_feature = "c", + all( + not(target_feature = "d"), + any(not(target_arch = "riscv32"), not(target_feature = "f")), + target_feature = "zca", + ) + )); /// "C" Extension for Compressed Instructions @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zca: "zca"; /// "Zca" Compressed Instructions excluding Floating-Point Loads/Stores @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zcf: "zcf"; - without cfg check: true; + implied by cfg(all(target_arch = "riscv32", target_feature = "c", target_feature = "f")); /// "Zcf" Compressed Instructions for Single-Precision Floating-Point Loads/Stores on RV32 @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zcd: "zcd"; - without cfg check: true; + implied by cfg(all(target_feature = "c", target_feature = "d")); /// "Zcd" Compressed Instructions for Double-Precision Floating-Point Loads/Stores @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zcb: "zcb"; /// "Zcb" Simple Code-size Saving Compressed Instructions From 74851f7cdfa953363dc3cbc7134e4a90a5b96b1c Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sun, 24 Aug 2025 08:34:15 +0000 Subject: [PATCH 5/6] std_detect: AArch64: Use `implied by cfg(...)` `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. --- library/std_detect/src/detect/arch/aarch64.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std_detect/src/detect/arch/aarch64.rs b/library/std_detect/src/detect/arch/aarch64.rs index 13570a25c1cfe..d95958b262bb8 100644 --- a/library/std_detect/src/detect/arch/aarch64.rs +++ b/library/std_detect/src/detect/arch/aarch64.rs @@ -110,10 +110,10 @@ features! { @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] asimd: "neon"; /// FEAT_AdvSIMD (Advanced SIMD/NEON) @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] pmull: "pmull"; - implied by target_features: ["aes"]; + implied by cfg(target_feature = "aes"); /// FEAT_PMULL (Polynomial Multiply) - Implied by `aes` target_feature @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] fp: "fp"; - implied by target_features: ["neon"]; + implied by cfg(target_feature = "neon"); /// FEAT_FP (Floating point support) - Implied by `neon` target_feature @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] aes: "aes"; /// FEAT_AES (AES SIMD instructions) & FEAT_PMULL (PMULL{2}, 64-bit operand variants) From 99d68f3232a7a813cc2342aed7824f82425e4478 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sun, 24 Aug 2025 08:34:15 +0000 Subject: [PATCH 6/6] std_detect: Remove support for `implied by target_features` This commit removes `implied by target_features: [...];` inside the target description macro `features!` (which is superseded by the `implied by cfg(...);` syntax). --- library/std_detect/src/detect/macros.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/library/std_detect/src/detect/macros.rs b/library/std_detect/src/detect/macros.rs index 0bdd72cbf4fda..21d22ced7fbf3 100644 --- a/library/std_detect/src/detect/macros.rs +++ b/library/std_detect/src/detect/macros.rs @@ -3,11 +3,7 @@ #[unstable(feature = "stdarch_internal", issue = "none")] macro_rules! detect_feature { ($feature:tt, $feature_lit:tt) => { - $crate::detect_feature!($feature, $feature_lit : $feature_lit) - }; - ($feature:tt, $feature_lit:tt : $($target_feature_lit:tt),*) => { - $(cfg!(target_feature = $target_feature_lit) ||)* - $crate::detect::__is_feature_detected::$feature() + cfg!(target_feature = $feature_lit) || $crate::detect::__is_feature_detected::$feature() }; ($feature:tt, $feature_lit:tt : cfg($target_feature_cfg:meta)) => { cfg!($target_feature_cfg) || $crate::detect::__is_feature_detected::$feature() @@ -20,10 +16,7 @@ macro_rules! detect_feature { #[allow(unused_macros, reason = "it's used in the features! macro below")] macro_rules! check_cfg_feature { ($feature:tt, $feature_lit:tt) => { - check_cfg_feature!($feature, $feature_lit : $feature_lit) - }; - ($feature:tt, $feature_lit:tt : $($target_feature_lit:tt),*) => { - $(cfg!(target_feature = $target_feature_lit);)* + cfg!(target_feature = $feature_lit); }; ($feature:tt, $feature_lit:tt : cfg($target_feature_cfg:meta)) => { cfg!($target_feature_cfg); @@ -47,7 +40,6 @@ macro_rules! features { $(@NO_RUNTIME_DETECTION: $nort_feature:tt; )* $(@FEATURE: #[$stability_attr:meta] $feature:ident: $feature_lit:tt; $(without cfg check: $feature_cfg_check:tt;)? - $(implied by target_features: [$($target_feature_lit:tt),*];)? $(implied by cfg($target_feature_cfg:meta);)? $(#[$feature_comment:meta])*)* ) => { @@ -63,7 +55,6 @@ macro_rules! features { $feature, $feature_lit $(, without cfg check: $feature_cfg_check)? - $(: $($target_feature_lit),*)? $(: cfg($target_feature_cfg))? ) }; @@ -154,7 +145,6 @@ macro_rules! features { $feature, $feature_lit $(, without cfg check: $feature_cfg_check)? - $(: $($target_feature_lit),*)? $(: cfg($target_feature_cfg))? ); )*