Summary
Make the is_x86_feature_detected! macro available in core on x86 and x86_64 targets.
Motivation
It's common for crates that only perform computation to sooner or later to get a request to work as no_std crates, so it should be easy for compute-only crates to be no_std crates. Also, (especially when SIMD is used) some crates that perform computation benefit from function multiversioning on x86 and x86_64. Multiversioning builds on the is_x86_feature_detected! macro.
is_x86_feature_detected! being in std but not in core causes a situation where no_std crates that benefit from multiversioning need to bother users of the crate with an std feature to explicitly opt into multiversioning when the user of the crate is actually OK with linking std.
If is_x86_feature_detected! was available in core, no_std crates wouldn't need bother crate users about multiversioning like this.
Guide-level explanation
The is_x86_feature_detected! macro is now available in core.
Reference-level explanation
On targets where executing the cpuid instruction is allowed and its results accurately describe what instruction set extensions are OK to use, core::is_x86_feature_detected! should work like std::is_x86_feature_detected! works today. This applies at least to x86 and x86_64 targets that currently have std in addition to having core.
On special targets without std, where either the cpuid instruction is not allowed or its answers don't correlate with what's OK to use, such as SGX or kernel-mode targets for kernels that e.g. don't save/restore register state across syscalls for all registers relevant to extensions reported as supported by cpuid, the responses of the is_x86_feature_detected! macro must depend on what target_features are statically known to be available rather than on querying cpuid.
Drawbacks
Making is_x86_feature_detected! available in core for targets where it cannot be run-time check using cpuid reduces clarity on what's a run-time check and what's not. (However, it's already the case that the macro promotes statically-answerable queries to static results, so the line is already fuzzy by design.)
Rationale and alternatives
As noted in the Motivation section above, is_x86_feature_detected! being in std complicates things for crates that are conceptually compute-only and otherwise could be no_std.
In practice, the mainstream usage of dispatch based on run-time availability of CPU features is pretty much all on the x86 and x86_64 architectures. Considering that this is the common case and in this common case, the detection works based on an instruction rather than a syscall, the common case should not be inconvenienced by the observation that on some other architectures CPU feature detection requires syscalls and, therefore, belongs in std. The macro already has "x86" in its name and is not available on those other architectures anyway.
That instruction-based detection might not work on special targets isn't a good enough reason to inconveniece common targets. A kernel-mode target might not save/restore FPU register state across syscalls and decide to refrain from using the FPU in kernel mode. Still, this isn't a reason to withhold floating-point functionality from core. Instead "this special target disallows cpuid" should modeled analogously to "this special target wants to refrain from emitting FPU operations".
Still letting is_x86_feature_detected! be available in core in such scenarios is likely more beneficial than withholding it, since having it available promotes code portability into special environments by letting is_x86_feature_detected! to resolve into cfg.
An alternative to moving is_x86_feature_detected! to core is to use the the core_detect crate. This alternative does not fully solve the problem, because if you depend on some other crate that rather mints an std feature than uses core_detect (as is the case with the multiversion crate), you are back to where you started due to dependencies.
Prior art
core_detect crate shows that x86 feature detection in no_std environment is feasible and practical.
core_detect uses code that comes from the standard library. In general, it's a sign of the standard library not meeting the needs of users well, when the relevant code exists in the standard library but is not available for use via the standard library (in relevant configurations) and the issue can be worked around by copying and pasting code from the standard library into a crate.