diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /library/stdarch/crates/core_arch/src/x86/bt.rs | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | library/stdarch/crates/core_arch/src/x86/bt.rs | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/library/stdarch/crates/core_arch/src/x86/bt.rs b/library/stdarch/crates/core_arch/src/x86/bt.rs new file mode 100644 index 000000000..338cb97a3 --- /dev/null +++ b/library/stdarch/crates/core_arch/src/x86/bt.rs @@ -0,0 +1,135 @@ +use crate::arch::asm; +#[cfg(test)] +use stdarch_test::assert_instr; + +// x32 wants to use a 32-bit address size, but asm! defaults to using the full +// register name (e.g. rax). We have to explicitly override the placeholder to +// use the 32-bit register name in that case. +#[cfg(target_pointer_width = "32")] +macro_rules! bt { + ($inst:expr) => { + concat!($inst, " {b:e}, ({p:e})") + }; +} +#[cfg(target_pointer_width = "64")] +macro_rules! bt { + ($inst:expr) => { + concat!($inst, " {b:e}, ({p})") + }; +} + +/// Returns the bit in position `b` of the memory addressed by `p`. +#[inline] +#[cfg_attr(test, assert_instr(bt))] +#[stable(feature = "simd_x86_bittest", since = "1.55.0")] +pub unsafe fn _bittest(p: *const i32, b: i32) -> u8 { + let r: u8; + asm!( + bt!("btl"), + "setc {r}", + p = in(reg) p, + b = in(reg) b, + r = out(reg_byte) r, + options(readonly, nostack, pure, att_syntax) + ); + r +} + +/// Returns the bit in position `b` of the memory addressed by `p`, then sets the bit to `1`. +#[inline] +#[cfg_attr(test, assert_instr(bts))] +#[stable(feature = "simd_x86_bittest", since = "1.55.0")] +pub unsafe fn _bittestandset(p: *mut i32, b: i32) -> u8 { + let r: u8; + asm!( + bt!("btsl"), + "setc {r}", + p = in(reg) p, + b = in(reg) b, + r = out(reg_byte) r, + options(nostack, att_syntax) + ); + r +} + +/// Returns the bit in position `b` of the memory addressed by `p`, then resets that bit to `0`. +#[inline] +#[cfg_attr(test, assert_instr(btr))] +#[stable(feature = "simd_x86_bittest", since = "1.55.0")] +pub unsafe fn _bittestandreset(p: *mut i32, b: i32) -> u8 { + let r: u8; + asm!( + bt!("btrl"), + "setc {r}", + p = in(reg) p, + b = in(reg) b, + r = out(reg_byte) r, + options(nostack, att_syntax) + ); + r +} + +/// Returns the bit in position `b` of the memory addressed by `p`, then inverts that bit. +#[inline] +#[cfg_attr(test, assert_instr(btc))] +#[stable(feature = "simd_x86_bittest", since = "1.55.0")] +pub unsafe fn _bittestandcomplement(p: *mut i32, b: i32) -> u8 { + let r: u8; + asm!( + bt!("btcl"), + "setc {r}", + p = in(reg) p, + b = in(reg) b, + r = out(reg_byte) r, + options(nostack, att_syntax) + ); + r +} + +#[cfg(test)] +mod tests { + use crate::core_arch::x86::*; + + #[test] + fn test_bittest() { + unsafe { + let a = 0b0101_0000i32; + assert_eq!(_bittest(&a as _, 4), 1); + assert_eq!(_bittest(&a as _, 5), 0); + } + } + + #[test] + fn test_bittestandset() { + unsafe { + let mut a = 0b0101_0000i32; + assert_eq!(_bittestandset(&mut a as _, 4), 1); + assert_eq!(_bittestandset(&mut a as _, 4), 1); + assert_eq!(_bittestandset(&mut a as _, 5), 0); + assert_eq!(_bittestandset(&mut a as _, 5), 1); + } + } + + #[test] + fn test_bittestandreset() { + unsafe { + let mut a = 0b0101_0000i32; + assert_eq!(_bittestandreset(&mut a as _, 4), 1); + assert_eq!(_bittestandreset(&mut a as _, 4), 0); + assert_eq!(_bittestandreset(&mut a as _, 5), 0); + assert_eq!(_bittestandreset(&mut a as _, 5), 0); + } + } + + #[test] + fn test_bittestandcomplement() { + unsafe { + let mut a = 0b0101_0000i32; + assert_eq!(_bittestandcomplement(&mut a as _, 4), 1); + assert_eq!(_bittestandcomplement(&mut a as _, 4), 0); + assert_eq!(_bittestandcomplement(&mut a as _, 4), 1); + assert_eq!(_bittestandcomplement(&mut a as _, 5), 0); + assert_eq!(_bittestandcomplement(&mut a as _, 5), 1); + } + } +} |