-
Notifications
You must be signed in to change notification settings - Fork 289
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Either this line (along with the corresponding There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sorry, I think I didn't fully gotten what you meant on the first read. I just changed the test to verify that calling That is, it should try to modify the eflags, see if they were modified, and then revert the modification before returning the result. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fn test_has_cpuid() {
unsafe {
let before = __readeflags();
if cpuid::has_cpuid() {
assert!(before != __readeflags());
} else {
assert!(before == __readeflags());
}
}
} is testing that |
||
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.