From 64f4ae86b11cc4e7ecde96ef66526a4815791c8a Mon Sep 17 00:00:00 2001 From: Muntasir Mahmud Date: Tue, 8 Sep 2026 20:16:57 +0600 Subject: [PATCH] cpufeatures: add support for avx10.1 and avx10.2 --- cpufeatures/README.md | 2 + cpufeatures/src/lib.rs | 1 + cpufeatures/src/x86.rs | 25 +++++- cpufeatures/tests/x86.rs | 168 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 195 insertions(+), 1 deletion(-) diff --git a/cpufeatures/README.md b/cpufeatures/README.md index ed240f05..0fc54ecf 100644 --- a/cpufeatures/README.md +++ b/cpufeatures/README.md @@ -101,6 +101,8 @@ Target features: - `adx` - `aes` - `avx` +- `avx10.1`* +- `avx10.2`* - `avx2` - `avx512bw`* - `avx512cd`* diff --git a/cpufeatures/src/lib.rs b/cpufeatures/src/lib.rs index a82add86..7dd94633 100644 --- a/cpufeatures/src/lib.rs +++ b/cpufeatures/src/lib.rs @@ -34,6 +34,7 @@ compile_error!("This crate works only on `aarch64`, `loongarch64`, `x86`, and `x #[macro_export] macro_rules! new { ($mod_name:ident, $($tf:tt),+ $(,)?) => { + #[allow(unexpected_cfgs)] mod $mod_name { use core::sync::atomic::{AtomicU8, Ordering::Relaxed}; diff --git a/cpufeatures/src/x86.rs b/cpufeatures/src/x86.rs index bf857729..0638501a 100644 --- a/cpufeatures/src/x86.rs +++ b/cpufeatures/src/x86.rs @@ -47,7 +47,13 @@ macro_rules! __detect_target_features { } let cr = unsafe { - [cpuid(1), cpuid_count(7, 0), cpuid_count(7, 1)] + [ + cpuid(1), + cpuid_count(7, 0), + cpuid_count(7, 1), + cpuid(0), + cpuid_count(0x24, 0), + ] }; $($crate::check!(cr, $tf) & )+ true @@ -81,6 +87,23 @@ macro_rules! __expand_check_macro { #[macro_export] #[doc(hidden)] macro_rules! check { + ($cr:expr, "avx10.1") => {{ + $crate::__xgetbv!($cr, 0b1110_0110) + & ($cr[3].eax >= 0x24) + & ($cr[2].edx & (1 << 19) != 0) + & (($cr[4].ebx & 0xff) >= 1) + & (($cr[4].ebx & (1 << 18)) != 0) + }}; + ($cr:expr, "avx10.2") => {{ + $crate::__xgetbv!($cr, 0b1110_0110) + & ($cr[3].eax >= 0x24) + & ($cr[2].edx & (1 << 19) != 0) + & (($cr[4].ebx & 0xff) >= 2) + & (($cr[4].ebx & (1 << 18)) != 0) + & ($cr[2].eax & (1 << 4) != 0) + & ($cr[2].edx & (1 << 4) != 0) + & ($cr[2].edx & (1 << 10) != 0) + }}; $( ($cr:expr, $name) => {{ // Register bits are listed here: diff --git a/cpufeatures/tests/x86.rs b/cpufeatures/tests/x86.rs index 8b1692b2..8e356219 100644 --- a/cpufeatures/tests/x86.rs +++ b/cpufeatures/tests/x86.rs @@ -3,6 +3,7 @@ #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] cpufeatures::new!(cpuid, "aes", "sha"); +cpufeatures::new!(cpuid_avx10, "avx10.1", "avx10.2"); #[test] fn init() { @@ -15,3 +16,170 @@ fn init_get() { let (token, val) = cpuid::init_get(); assert_eq!(val, token.get()); } + +#[test] +fn avx10_probe_does_not_fault() { + let (token, val) = cpuid_avx10::init_get(); + assert_eq!(val, token.get()); + let _ = cpuid_avx10::get(); +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +mod avx10_logic { + #[cfg(target_arch = "x86")] + use core::arch::x86::CpuidResult; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::CpuidResult; + + fn leaf1() -> CpuidResult { + CpuidResult { + eax: 0, + ebx: 0, + ecx: 0b11 << 26, + edx: 0, + } + } + + fn blank() -> CpuidResult { + CpuidResult { + eax: 0, + ebx: 0, + ecx: 0, + edx: 0, + } + } + + #[test] + fn version_zero_is_disabled() { + let cr = [ + leaf1(), + blank(), + CpuidResult { + eax: 0, + ebx: 0, + ecx: 0, + edx: 1 << 19, + }, + CpuidResult { + eax: 0x24, + ebx: 0, + ecx: 0, + edx: 0, + }, + CpuidResult { + eax: 0, + ebx: (1 << 17) | (1 << 18), + ecx: 0, + edx: 0, + }, + ]; + assert!(!cpufeatures::check!(cr, "avx10.1")); + assert!(!cpufeatures::check!(cr, "avx10.2")); + } + + #[test] + fn max_leaf_guard_holds() { + let cr = [ + leaf1(), + blank(), + CpuidResult { + eax: 0, + ebx: 0, + ecx: 0, + edx: 1 << 19, + }, + CpuidResult { + eax: 0x16, + ebx: 0, + ecx: 0, + edx: 0, + }, + CpuidResult { + eax: 0, + ebx: 1 | (1 << 17) | (1 << 18), + ecx: 0, + edx: 0, + }, + ]; + assert!(!cpufeatures::check!(cr, "avx10.1")); + assert!(!cpufeatures::check!(cr, "avx10.2")); + } + + #[test] + fn presence_bit_required() { + let cr = [ + leaf1(), + blank(), + blank(), + CpuidResult { + eax: 0x24, + ebx: 0, + ecx: 0, + edx: 0, + }, + CpuidResult { + eax: 0, + ebx: 1 | (1 << 17) | (1 << 18), + ecx: 0, + edx: 0, + }, + ]; + assert!(!cpufeatures::check!(cr, "avx10.1")); + assert!(!cpufeatures::check!(cr, "avx10.2")); + } + + #[test] + fn narrow_vector_without_512_bit_reports_false() { + let cr = [ + leaf1(), + blank(), + CpuidResult { + eax: 0, + ebx: 0, + ecx: 0, + edx: 1 << 19, + }, + CpuidResult { + eax: 0x24, + ebx: 0, + ecx: 0, + edx: 0, + }, + CpuidResult { + eax: 0, + ebx: 1 | (1 << 17), + ecx: 0, + edx: 0, + }, + ]; + assert!(!cpufeatures::check!(cr, "avx10.1")); + assert!(!cpufeatures::check!(cr, "avx10.2")); + } + + #[test] + fn vnni_trio_required_for_avx10_2() { + let cr = [ + leaf1(), + blank(), + CpuidResult { + eax: 0, + ebx: 0, + ecx: 0, + edx: 1 << 19, + }, + CpuidResult { + eax: 0x24, + ebx: 0, + ecx: 0, + edx: 0, + }, + CpuidResult { + eax: 0, + ebx: 2 | (1 << 18), + ecx: 0, + edx: 0, + }, + ]; + assert!(!cpufeatures::check!(cr, "avx10.2")); + } +}