#![no_std]
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
compile_error!("This crate works only on x86 and x86-64 targets.");
#[macro_export]
macro_rules! new {
($mod_name:ident, $($tf:tt),+ $(,)? ) => {
mod $mod_name {
use core::sync::atomic::{AtomicU8, Ordering::Relaxed};
const UNINIT: u8 = u8::max_value();
static STORAGE: AtomicU8 = AtomicU8::new(UNINIT);
#[derive(Copy, Clone, Debug)]
pub struct InitToken(());
impl InitToken {
#[inline(always)]
pub fn get(&self) -> bool {
#[cfg(all(not(target_env = "sgx"), not(all($(target_feature=$tf, )*))))]
let res = STORAGE.load(Relaxed) == 1;
#[cfg(all(target_env = "sgx", not(all($(target_feature=$tf, )*))))]
let res = false;
#[cfg(all($(target_feature=$tf, )*))]
let res = true;
res
}
}
#[inline]
pub fn init_get() -> (InitToken, bool) {
#[cfg(all(not(target_env = "sgx"), not(all($(target_feature=$tf, )*))))]
let res = {
#[cfg(target_arch = "x86")]
use core::arch::x86::{__cpuid, __cpuid_count};
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::{__cpuid, __cpuid_count};
let val = STORAGE.load(Relaxed);
if val == UNINIT {
#[allow(unused_variables)]
let cr = unsafe {
[__cpuid(1), __cpuid_count(7, 0)]
};
let res = $(cpuid_bool::check!(cr, $tf) & )+ true;
STORAGE.store(res as u8, Relaxed);
res
} else {
val == 1
}
};
#[cfg(all(target_env = "sgx", not(all($(target_feature=$tf, )*))))]
let res = false;
#[cfg(all($(target_feature=$tf, )*))]
let res = true;
(InitToken(()), res)
}
#[inline]
pub fn init() -> InitToken {
init_get().0
}
#[inline]
pub fn get() -> bool {
init_get().1
}
}
};
}
macro_rules! expand_check_macro {
($(($name:tt, $i:expr, $reg:ident, $offset:expr)),* $(,)?) => {
#[macro_export]
#[doc(hidden)]
macro_rules! check {
$(
($cr:expr, $name) => { ($cr[$i].$reg & (1 << $offset) != 0) };
)*
}
};
}
expand_check_macro! {
("mmx", 0, edx, 23),
("sse", 0, edx, 25),
("sse2", 0, edx, 26),
("sse3", 0, ecx, 0),
("pclmulqdq", 0, ecx, 1),
("ssse3", 0, ecx, 9),
("fma", 0, ecx, 12),
("sse4.1", 0, ecx, 19),
("sse4.2", 0, ecx, 20),
("popcnt", 0, ecx, 23),
("aes", 0, ecx, 25),
("avx", 0, ecx, 28),
("rdrand", 0, ecx, 30),
("sgx", 1, ebx, 2),
("bmi1", 1, ebx, 3),
("avx2", 1, ebx, 5),
("bmi2", 1, ebx, 8),
("rdseed", 1, ebx, 18),
("adx", 1, ebx, 19),
("sha", 1, ebx, 29),
}