1#[macro_export]
12#[doc(hidden)]
13macro_rules! __unless_target_features {
14 ($($tf:tt),+ => $body:expr ) => {{
15 #[cfg(not(all($(target_feature=$tf,)*)))]
16 {
17 #[cfg(not(any(target_env = "sgx", target_os = "none", target_os = "uefi")))]
18 $body
19
20 #[cfg(any(target_env = "sgx", target_os = "none", target_os = "uefi"))]
23 false
24 }
25
26 #[cfg(all($(target_feature=$tf,)*))]
27 true
28 }};
29}
30
31#[macro_export]
33#[doc(hidden)]
34macro_rules! __detect_target_features {
35 ($($tf:tt),+) => {{
36 #[cfg(target_arch = "x86")]
37 use core::arch::x86::{__cpuid, __cpuid_count, CpuidResult};
38 #[cfg(target_arch = "x86_64")]
39 use core::arch::x86_64::{__cpuid, __cpuid_count, CpuidResult};
40
41 unsafe fn cpuid(leaf: u32) -> CpuidResult {
42 __cpuid(leaf)
43 }
44
45 unsafe fn cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
46 __cpuid_count(leaf, sub_leaf)
47 }
48
49 let cr = unsafe {
50 [cpuid(1), cpuid_count(7, 0), cpuid_count(7, 1)]
51 };
52
53 $($crate::check!(cr, $tf) & )+ true
54 }};
55}
56
57#[macro_export]
59#[doc(hidden)]
60macro_rules! __xgetbv {
61 ($cr:expr, $mask:expr) => {{
62 #[cfg(target_arch = "x86")]
63 use core::arch::x86 as arch;
64 #[cfg(target_arch = "x86_64")]
65 use core::arch::x86_64 as arch;
66
67 let xmask = 0b11 << 26;
69 let xsave = $cr[0].ecx & xmask == xmask;
70 if xsave {
71 let xcr0 = unsafe { arch::_xgetbv(arch::_XCR_XFEATURE_ENABLED_MASK) };
72 (xcr0 & $mask) == $mask
73 } else {
74 false
75 }
76 }};
77}
78
79macro_rules! __expand_check_macro {
80 ($(($name:tt, $reg_cap:tt $(, $i:expr, $reg:ident, $offset:expr)*)),* $(,)?) => {
81 #[macro_export]
82 #[doc(hidden)]
83 macro_rules! check {
84 $(
85 ($cr:expr, $name) => {{
86 let reg_cap = match $reg_cap {
89 "xmm" => $crate::__xgetbv!($cr, 0b10),
91 "ymm" => $crate::__xgetbv!($cr, 0b110),
93 "zmm" => $crate::__xgetbv!($cr, 0b1110_0110),
95 _ => true,
96 };
97 reg_cap
98 $(
99 & ($cr[$i].$reg & (1 << $offset) != 0)
100 )*
101 }};
102 )*
103 }
104 };
105}
106
107#[macro_export]
#[doc(hidden)]
macro_rules! check {
($cr : expr, "sse3") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [0].ecx & (1 << 0) != 0)
}}; ($cr : expr, "pclmulqdq") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [0].ecx & (1 << 1) != 0)
}}; ($cr : expr, "ssse3") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [0].ecx & (1 << 9) != 0)
}}; ($cr : expr, "fma") =>
{{
let reg_cap = match
"ymm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [0].ecx & (1 << 12) != 0) &
($cr [0].ecx & (1 << 28) != 0)
}}; ($cr : expr, "sse4.1") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [0].ecx & (1 << 19) != 0)
}}; ($cr : expr, "sse4.2") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [0].ecx & (1 << 20) != 0)
}}; ($cr : expr, "popcnt") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [0].ecx & (1 << 23) != 0)
}}; ($cr : expr, "aes") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [0].ecx & (1 << 25) != 0)
}}; ($cr : expr, "avx") =>
{{
let reg_cap = match
"ymm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [0].ecx & (1 << 28) != 0)
}}; ($cr : expr, "rdrand") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [0].ecx & (1 << 30) != 0)
}}; ($cr : expr, "mmx") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [0].edx & (1 << 23) != 0)
}}; ($cr : expr, "sse") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [0].edx & (1 << 25) != 0)
}}; ($cr : expr, "sse2") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [0].edx & (1 << 26) != 0)
}}; ($cr : expr, "sgx") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ebx & (1 << 2) != 0)
}}; ($cr : expr, "bmi1") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ebx & (1 << 3) != 0)
}}; ($cr : expr, "bmi2") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ebx & (1 << 8) != 0)
}}; ($cr : expr, "avx2") =>
{{
let reg_cap = match
"ymm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ebx & (1 << 5) != 0) &
($cr [0].ecx & (1 << 28) != 0)
}}; ($cr : expr, "avx512f") =>
{{
let reg_cap = match
"zmm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ebx & (1 << 16) != 0)
}}; ($cr : expr, "avx512dq") =>
{{
let reg_cap = match
"zmm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ebx & (1 << 17) != 0)
}}; ($cr : expr, "rdseed") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ebx & (1 << 18) != 0)
}}; ($cr : expr, "adx") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ebx & (1 << 19) != 0)
}}; ($cr : expr, "avx512ifma") =>
{{
let reg_cap = match
"zmm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ebx & (1 << 21) != 0)
}}; ($cr : expr, "avx512pf") =>
{{
let reg_cap = match
"zmm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ebx & (1 << 26) != 0)
}}; ($cr : expr, "avx512er") =>
{{
let reg_cap = match
"zmm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ebx & (1 << 27) != 0)
}}; ($cr : expr, "avx512cd") =>
{{
let reg_cap = match
"zmm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ebx & (1 << 28) != 0)
}}; ($cr : expr, "sha") =>
{{
let reg_cap = match
""{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ebx & (1 << 29) != 0)
}}; ($cr : expr, "avx512bw") =>
{{
let reg_cap = match
"zmm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ebx & (1 << 30) != 0)
}}; ($cr : expr, "avx512vl") =>
{{
let reg_cap = match
"zmm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ebx & (1 << 31) != 0)
}}; ($cr : expr, "avx512vbmi") =>
{{
let reg_cap = match
"zmm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ecx & (1 << 1) != 0)
}}; ($cr : expr, "avx512vbmi2") =>
{{
let reg_cap = match
"zmm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ecx & (1 << 6) != 0)
}}; ($cr : expr, "gfni") =>
{{
let reg_cap = match
"zmm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ecx & (1 << 8) != 0)
}}; ($cr : expr, "vaes") =>
{{
let reg_cap = match
"zmm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ecx & (1 << 9) != 0)
}}; ($cr : expr, "vpclmulqdq") =>
{{
let reg_cap = match
"zmm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ecx & (1 << 10) != 0)
}}; ($cr : expr, "avx512bitalg") =>
{{
let reg_cap = match
"zmm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ecx & (1 << 12) != 0)
}}; ($cr : expr, "avx512vpopcntdq") =>
{{
let reg_cap = match
"zmm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [1].ecx & (1 << 14) != 0)
}}; ($cr : expr, "sha512") =>
{{
let reg_cap = match
"ymm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [2].eax & (1 << 0) != 0)
}}; ($cr : expr, "sm3") =>
{{
let reg_cap = match
"xmm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [2].eax & (1 << 1) != 0)
}}; ($cr : expr, "sm4") =>
{{
let reg_cap = match
"ymm"{
"xmm" => crate :: __xgetbv! ($cr, 0b10), "ymm" => crate ::
__xgetbv! ($cr, 0b110), "zmm" => crate :: __xgetbv!
($cr, 0b1110_0110), _ => true,
}; reg_cap & ($cr [2].eax & (1 << 2) != 0)
}};
}__expand_check_macro! {
108 ("sse3", "", 0, ecx, 0),
109 ("pclmulqdq", "", 0, ecx, 1),
110 ("ssse3", "", 0, ecx, 9),
111 ("fma", "ymm", 0, ecx, 12, 0, ecx, 28),
112 ("sse4.1", "", 0, ecx, 19),
113 ("sse4.2", "", 0, ecx, 20),
114 ("popcnt", "", 0, ecx, 23),
115 ("aes", "", 0, ecx, 25),
116 ("avx", "ymm", 0, ecx, 28),
117 ("rdrand", "", 0, ecx, 30),
118
119 ("mmx", "", 0, edx, 23),
120 ("sse", "", 0, edx, 25),
121 ("sse2", "", 0, edx, 26),
122
123 ("sgx", "", 1, ebx, 2),
124 ("bmi1", "", 1, ebx, 3),
125 ("bmi2", "", 1, ebx, 8),
126 ("avx2", "ymm", 1, ebx, 5, 0, ecx, 28),
127 ("avx512f", "zmm", 1, ebx, 16),
128 ("avx512dq", "zmm", 1, ebx, 17),
129 ("rdseed", "", 1, ebx, 18),
130 ("adx", "", 1, ebx, 19),
131 ("avx512ifma", "zmm", 1, ebx, 21),
132 ("avx512pf", "zmm", 1, ebx, 26),
133 ("avx512er", "zmm", 1, ebx, 27),
134 ("avx512cd", "zmm", 1, ebx, 28),
135 ("sha", "", 1, ebx, 29),
136 ("avx512bw", "zmm", 1, ebx, 30),
137 ("avx512vl", "zmm", 1, ebx, 31),
138 ("avx512vbmi", "zmm", 1, ecx, 1),
139 ("avx512vbmi2", "zmm", 1, ecx, 6),
140 ("gfni", "zmm", 1, ecx, 8),
141 ("vaes", "zmm", 1, ecx, 9),
142 ("vpclmulqdq", "zmm", 1, ecx, 10),
143 ("avx512bitalg", "zmm", 1, ecx, 12),
144 ("avx512vpopcntdq", "zmm", 1, ecx, 14),
145
146 ("sha512", "ymm", 2, eax, 0),
147 ("sm3", "xmm", 2, eax, 1),
148 ("sm4", "ymm", 2, eax, 2),
149}