portable_atomic/imp/detect/
x86_64.rs1#![cfg_attr(portable_atomic_sanitize_thread, allow(dead_code))]
10
11#[cfg(any(target_env = "sgx", miri))]
14compile_error!("internal error: this module is not supported on this environment");
15
16include!("common.rs");
17
18#[cfg(not(portable_atomic_no_asm))]
19use core::arch::asm;
20use core::arch::x86_64::CpuidResult;
21
22#[cfg(not(target_env = "sgx"))]
30fn __cpuid(leaf: u32) -> CpuidResult {
31 let eax;
32 let mut ebx;
33 let ecx;
34 let edx;
35 unsafe {
39 asm!(
40 "mov {ebx_tmp:r}, rbx", "cpuid",
42 "xchg {ebx_tmp:r}, rbx", ebx_tmp = out(reg) ebx,
44 inout("eax") leaf => eax,
45 inout("ecx") 0 => ecx,
46 out("edx") edx,
47 options(nostack, preserves_flags),
48 );
49 }
50 CpuidResult { eax, ebx, ecx, edx }
51}
52
53const _VENDOR_ID_INTEL: [u8; 12] = *b"GenuineIntel"; const _VENDOR_ID_INTEL2: [u8; 12] = *b"GenuineIotel"; const _VENDOR_ID_AMD: [u8; 12] = *b"AuthenticAMD"; const _VENDOR_ID_ZHAOXIN: [u8; 12] = *b" Shanghai "; fn _vendor_id() -> [u8; 12] {
59 let CpuidResult { ebx, ecx, edx, .. } = __cpuid(0);
61 let vendor_id: [[u8; 4]; 3] = [ebx.to_ne_bytes(), edx.to_ne_bytes(), ecx.to_ne_bytes()];
62 unsafe { core::mem::transmute(vendor_id) }
64}
65fn _vendor_has_vmovdqa_atomic(vendor_id: [u8; 12]) -> bool {
66 vendor_id == _VENDOR_ID_INTEL
69 || vendor_id == _VENDOR_ID_INTEL2
70 || vendor_id == _VENDOR_ID_AMD
71 || vendor_id == _VENDOR_ID_ZHAOXIN
72}
73
74#[cold]
75fn _detect(info: &mut CpuInfo) {
76 let proc_info_ecx = __cpuid(0x0000_0001_u32).ecx;
77
78 if test(proc_info_ecx, 13) {
80 info.set(CpuInfo::HAS_CMPXCHG16B);
81 }
82
83 #[cfg(target_feature = "sse")]
85 {
86 use core::arch::x86_64::_xgetbv;
87
88 let cpu_xsave = test(proc_info_ecx, 26);
90 if cpu_xsave {
91 let cpu_osxsave = test(proc_info_ecx, 27);
92 if cpu_osxsave {
93 let xcr0 = unsafe { _xgetbv(0) };
96 let os_avx_support = xcr0 & 6 == 6;
97 if os_avx_support && test(proc_info_ecx, 28) {
98 let vendor_id = _vendor_id();
99 if _vendor_has_vmovdqa_atomic(vendor_id) {
100 info.set(CpuInfo::HAS_VMOVDQA_ATOMIC);
101 }
102 }
103 }
104 }
105 }
106}
107
108#[allow(
109 clippy::alloc_instead_of_core,
110 clippy::std_instead_of_alloc,
111 clippy::std_instead_of_core,
112 clippy::undocumented_unsafe_blocks,
113 clippy::wildcard_imports
114)]
115#[cfg(test)]
116mod tests {
117 use std::io::{self, Write};
118
119 use super::*;
120
121 #[test]
122 #[cfg_attr(portable_atomic_test_outline_atomics_detect_false, ignore)]
123 fn test_cpuid() {
124 assert_eq!(std::is_x86_feature_detected!("cmpxchg16b"), detect().has_cmpxchg16b());
125 let vendor_id = _vendor_id();
126 {
127 let stdout = io::stderr();
128 let mut stdout = stdout.lock();
129 let _ = writeln!(stdout, "\n vendor_id: {}", std::str::from_utf8(&vendor_id).unwrap());
130 }
131 if _vendor_has_vmovdqa_atomic(vendor_id) {
132 assert_eq!(std::is_x86_feature_detected!("avx"), detect().has_vmovdqa_atomic());
133 } else {
134 assert!(!detect().has_vmovdqa_atomic());
135 }
136 }
137}