#![allow(clippy::module_name_repetitions)]
#[cfg(test)]
use stdsimd_test::assert_instr;
#[allow(clippy::missing_inline_in_public_items)]
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub struct CpuidResult {
#[stable(feature = "simd_x86", since = "1.27.0")]
pub eax: u32,
#[stable(feature = "simd_x86", since = "1.27.0")]
pub ebx: u32,
#[stable(feature = "simd_x86", since = "1.27.0")]
pub ecx: u32,
#[stable(feature = "simd_x86", since = "1.27.0")]
pub edx: u32,
}
#[inline]
#[cfg_attr(test, assert_instr(cpuid))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
let eax;
let ebx;
let ecx;
let edx;
#[cfg(target_arch = "x86")]
{
asm!("cpuid"
: "={eax}"(eax), "={ebx}"(ebx), "={ecx}"(ecx), "={edx}"(edx)
: "{eax}"(leaf), "{ecx}"(sub_leaf)
: :);
}
#[cfg(target_arch = "x86_64")]
{
asm!("cpuid\n"
: "={eax}"(eax), "={ebx}"(ebx), "={ecx}"(ecx), "={edx}"(edx)
: "{eax}"(leaf), "{ecx}"(sub_leaf)
: "rbx" :);
}
CpuidResult { eax, ebx, ecx, edx }
}
#[inline]
#[cfg_attr(test, assert_instr(cpuid))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __cpuid(leaf: u32) -> CpuidResult {
__cpuid_count(leaf, 0)
}
#[inline]
pub fn has_cpuid() -> bool {
#[cfg(target_env = "sgx")]
{
false
}
#[cfg(all(not(target_env = "sgx"), target_arch = "x86_64"))]
{
true
}
#[cfg(all(not(target_env = "sgx"), target_arch = "x86"))]
{
#[cfg(target_feature = "sse")]
{
true
}
#[cfg(not(target_feature = "sse"))]
unsafe {
let result: u32;
let _temp: u32;
asm!(r#"
# Read eflags into $0 and copy it into $1:
pushfd
pop $0
mov $1, $0
# Flip 21st bit of $0.
xor $0, 0x200000
# Set eflags to the value of $0
#
# Bit 21st can only be modified if cpuid is available
push $0
popfd # A
# Read eflags into $0:
pushfd # B
pop $0
# xor with the original eflags sets the bits that
# have been modified:
xor $0, $1
"#
: "=r"(result), "=r"(_temp)
:
: "cc", "memory"
: "intel");
(result & 0x200000) != 0
}
}
}
#[inline]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __get_cpuid_max(leaf: u32) -> (u32, u32) {
let CpuidResult { eax, ebx, .. } = __cpuid(leaf);
(eax, ebx)
}
#[cfg(test)]
mod tests {
use crate::core_arch::x86::*;
#[test]
fn test_always_has_cpuid() {
assert!(cpuid::has_cpuid());
}
#[test]
fn test_has_cpuid_idempotent() {
assert_eq!(cpuid::has_cpuid(), cpuid::has_cpuid());
}
}