Crate core_detect[−][src]
This crate provides a no_std
version of std’s is_x86_feature_detected!
macro.
This is possible because x86 chips can just use the cpuid
instruction to
detect CPU features, whereas most other architectures require either reading
files or querying the OS.
Usage
if core_detect::is_x86_feature_detected!("ssse3") { println!("SSSE3 is available"); }
Note that like the equivalent macro in std
, this will error
on architectures other than x86/x86_64, so you should put the code behind a
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
check.
(In the future, this crate may provide another macro which returns false in these cases instead, and supports testing multiple features simultaneously).
Caveats
The cpuid
instruction doesn’t exist on all x86 machines, it was added
around 1994. (It’s also not available on SGX, but this doesn’t cause any
issues since we can check that with cfg(target_env = "sgx")
).
If you run cpuid
on a machine older than that, it causes an illegal
instruction fault (SIGILL). Unfortunately, there’s no good stable way to
reliably determine if cpuid
will fault in stable rust: A
core::arch::x86::has_cpuid
function exists, but didn’t stabilize with the rest of core::arch::x86
,
and the only way to implement it ourselves is with inline asm, which… is
also still unstable.
For what it’s worth, it’s actually pretty uncommon that we’d need to call
has_cpuid
on common rust targets, since we perform the following compile
time checks:
- We never have cpuid on
target_env = "sgx"
(as mentioned). - We always have cpuid on
target_arch = "x86_64"
. - And we always have cpuid if
target_feature = "sse"
(which covers thei686-*
targets).
Unfortunately, if none of those applies… we don’t know if calling CPUID will crash the process. This library has a few ways it can handle this:
-
Cautiously (the default): In this mode, we conceptually swap
has_cpuid
out with a function that always returns false. That is: we never call it unless we’re sure it wont crash the process. -
Recklessly (
feature = "assume_has_cpuid"
): This is essentially the opposite of the last one — assumehas_cpuid
would have returned true, and callcpuid
anyway.In practice, this should be fine. These machines are rare now (they’re over 30 years old…), and pretty only are common through QEMU, and even then, usually after a misconfiguration.
If you do happen to run the instruction, the process crashes, but in a controlled manner — Executing an illegal instruction to tringger a SIGILL is what
core::intrinsics::abort
does on x86, so it’s not dangerous or anything. -
Using unstable nightly features (
feature = "unstable_has_cpuid"
): This approach requires a nightly compiler, but has no other major downsides, besides the fact that thehas_cpuid
function could vanish at any time.
Eventually, inline asm will stabilize and we can solve this problem more cleanly.
Macros
is_x86_feature_detected | A macro to test at runtime whether a CPU feature is available on x86/x86-64 platforms. |