-
Notifications
You must be signed in to change notification settings - Fork 309
Fix has_cpuid implementation #492
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
7f12738
a374f60
f87c949
5760ad3
b12aef6
277a49a
3605ad3
c70093b
6ee5955
9f9427e
1831237
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -86,26 +86,37 @@ pub fn has_cpuid() -> bool { | |
| } | ||
| #[cfg(target_arch = "x86")] | ||
| { | ||
| use coresimd::x86::{__readeflags, __writeeflags}; | ||
|
|
||
| // On `x86` the `cpuid` instruction is not always available. | ||
| // This follows the approach indicated in: | ||
| // http://wiki.osdev.org/CPUID#Checking_CPUID_availability | ||
| unsafe { | ||
| // Read EFLAGS: | ||
| let eflags: u32 = __readeflags(); | ||
|
|
||
| // Invert the ID bit in EFLAGS: | ||
| let eflags_mod: u32 = eflags | 0x0020_0000; | ||
|
|
||
| // Store the modified EFLAGS (ID bit may or may not be inverted) | ||
| __writeeflags(eflags_mod); | ||
|
|
||
| // Read EFLAGS again: | ||
| let eflags_after: u32 = __readeflags(); | ||
|
|
||
| // Check if the ID bit changed: | ||
| eflags_after != eflags | ||
| // On `x86` the `cpuid` instruction is not always available. | ||
| // This follows the approach indicated in: | ||
| // http://wiki.osdev.org/CPUID#Checking_CPUID_availability | ||
| // https://software.intel.com/en-us/articles/using-cpuid-to-detect-the-presence-of-sse-41-and-sse-42-instruction-sets/ | ||
| // which detects whether `cpuid` is available by checking whether the 21th bit of the EFLAGS register is modifiable or not. | ||
| // If it is, then `cpuid` is available. | ||
| let eax: i32; | ||
| asm!(r#" | ||
| push %ecx | ||
| pushfd | ||
| pushfd | ||
| pop %eax | ||
| mov %ecx, %eax | ||
| xor %eax, 0x200000 | ||
| push %eax | ||
| popfd | ||
| pushfd | ||
| pop %eax | ||
| xor %eax, %ecx | ||
| shrd %eax, 21 | ||
| popfd | ||
|
||
| pop %ecx | ||
| "# | ||
| : "={eax}"(eax) // output operands | ||
| : // input operands | ||
| : "memory", "ecx" // clobbers all memory | ||
| : "volatile" // has side-effects | ||
| ); | ||
| debug_assert!(eax == 0 || eax == 1); | ||
| eax == 1 | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -138,6 +149,11 @@ mod tests { | |
| assert!(cpuid::has_cpuid()); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_has_cpuid_idempotent() { | ||
| assert_eq!(cpuid::has_cpuid(), cpuid::has_cpuid()); | ||
| } | ||
|
|
||
| #[cfg(target_arch = "x86")] | ||
| #[test] | ||
| fn test_has_cpuid() { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the problem is that this is the instruction for doubles, it should be shr, or shrl, but none of these appear to work.