diff --git a/crates/core_arch/src/x86/bt.rs b/crates/core_arch/src/x86/bt.rs new file mode 100644 index 0000000000..8ecc87fe4c --- /dev/null +++ b/crates/core_arch/src/x86/bt.rs @@ -0,0 +1,102 @@ +#[cfg(test)] +use stdsimd_test::assert_instr; + +/// Returns the bit in position `b` of the memory addressed by `p`. +#[inline] +#[cfg_attr(test, assert_instr(bt))] +#[unstable(feature = "simd_x86_bittest", issue = "59414")] +pub unsafe fn _bittest(p: *const i32, b: i32) -> u8 { + let r: u8; + asm!("btl $2, $1\n\tsetc ${0:b}" + : "=r"(r) + : "*m"(p), "r"(b) + : "cc", "memory"); + 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))] +#[unstable(feature = "simd_x86_bittest", issue = "59414")] +pub unsafe fn _bittestandset(p: *mut i32, b: i32) -> u8 { + let r: u8; + asm!("btsl $2, $1\n\tsetc ${0:b}" + : "=r"(r), "+*m"(p) + : "r"(b) + : "cc", "memory"); + 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))] +#[unstable(feature = "simd_x86_bittest", issue = "59414")] +pub unsafe fn _bittestandreset(p: *mut i32, b: i32) -> u8 { + let r: u8; + asm!("btrl $2, $1\n\tsetc ${0:b}" + : "=r"(r), "+*m"(p) + : "r"(b) + : "cc", "memory"); + r +} + +/// Returns the bit in position `b` of the memory addressed by `p`, then inverts that bit. +#[inline] +#[cfg_attr(test, assert_instr(btc))] +#[unstable(feature = "simd_x86_bittest", issue = "59414")] +pub unsafe fn _bittestandcomplement(p: *mut i32, b: i32) -> u8 { + let r: u8; + asm!("btcl $2, $1\n\tsetc ${0:b}" + : "=r"(r), "+*m"(p) + : "r"(b) + : "cc", "memory"); + 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); + } + } +} diff --git a/crates/core_arch/src/x86/mod.rs b/crates/core_arch/src/x86/mod.rs index c0d39d2873..5f28aa8836 100644 --- a/crates/core_arch/src/x86/mod.rs +++ b/crates/core_arch/src/x86/mod.rs @@ -562,3 +562,6 @@ pub use self::avx512f::*; mod avx512ifma; pub use self::avx512ifma::*; + +mod bt; +pub use self::bt::*; diff --git a/crates/core_arch/src/x86_64/bt.rs b/crates/core_arch/src/x86_64/bt.rs new file mode 100644 index 0000000000..c6de6b28d5 --- /dev/null +++ b/crates/core_arch/src/x86_64/bt.rs @@ -0,0 +1,102 @@ +#[cfg(test)] +use stdsimd_test::assert_instr; + +/// Returns the bit in position `b` of the memory addressed by `p`. +#[inline] +#[cfg_attr(test, assert_instr(bt))] +#[unstable(feature = "simd_x86_bittest", issue = "59414")] +pub unsafe fn _bittest64(p: *const i64, b: i64) -> u8 { + let r: u8; + asm!("btq $2, $1\n\tsetc ${0:b}" + : "=r"(r) + : "*m"(p), "r"(b) + : "cc", "memory"); + 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))] +#[unstable(feature = "simd_x86_bittest", issue = "59414")] +pub unsafe fn _bittestandset64(p: *mut i64, b: i64) -> u8 { + let r: u8; + asm!("btsq $2, $1\n\tsetc ${0:b}" + : "=r"(r), "+*m"(p) + : "r"(b) + : "cc", "memory"); + 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))] +#[unstable(feature = "simd_x86_bittest", issue = "59414")] +pub unsafe fn _bittestandreset64(p: *mut i64, b: i64) -> u8 { + let r: u8; + asm!("btrq $2, $1\n\tsetc ${0:b}" + : "=r"(r), "+*m"(p) + : "r"(b) + : "cc", "memory"); + r +} + +/// Returns the bit in position `b` of the memory addressed by `p`, then inverts that bit. +#[inline] +#[cfg_attr(test, assert_instr(btc))] +#[unstable(feature = "simd_x86_bittest", issue = "59414")] +pub unsafe fn _bittestandcomplement64(p: *mut i64, b: i64) -> u8 { + let r: u8; + asm!("btcq $2, $1\n\tsetc ${0:b}" + : "=r"(r), "+*m"(p) + : "r"(b) + : "cc", "memory"); + r +} + +#[cfg(test)] +mod tests { + use crate::core_arch::x86_64::*; + + #[test] + fn test_bittest64() { + unsafe { + let a = 0b0101_0000i64; + assert_eq!(_bittest64(&a as _, 4), 1); + assert_eq!(_bittest64(&a as _, 5), 0); + } + } + + #[test] + fn test_bittestandset64() { + unsafe { + let mut a = 0b0101_0000i64; + assert_eq!(_bittestandset64(&mut a as _, 4), 1); + assert_eq!(_bittestandset64(&mut a as _, 4), 1); + assert_eq!(_bittestandset64(&mut a as _, 5), 0); + assert_eq!(_bittestandset64(&mut a as _, 5), 1); + } + } + + #[test] + fn test_bittestandreset64() { + unsafe { + let mut a = 0b0101_0000i64; + assert_eq!(_bittestandreset64(&mut a as _, 4), 1); + assert_eq!(_bittestandreset64(&mut a as _, 4), 0); + assert_eq!(_bittestandreset64(&mut a as _, 5), 0); + assert_eq!(_bittestandreset64(&mut a as _, 5), 0); + } + } + + #[test] + fn test_bittestandcomplement64() { + unsafe { + let mut a = 0b0101_0000i64; + assert_eq!(_bittestandcomplement64(&mut a as _, 4), 1); + assert_eq!(_bittestandcomplement64(&mut a as _, 4), 0); + assert_eq!(_bittestandcomplement64(&mut a as _, 4), 1); + assert_eq!(_bittestandcomplement64(&mut a as _, 5), 0); + assert_eq!(_bittestandcomplement64(&mut a as _, 5), 1); + } + } +} diff --git a/crates/core_arch/src/x86_64/mod.rs b/crates/core_arch/src/x86_64/mod.rs index ca16e4f17b..038f6478cc 100644 --- a/crates/core_arch/src/x86_64/mod.rs +++ b/crates/core_arch/src/x86_64/mod.rs @@ -44,3 +44,6 @@ pub use self::cmpxchg16b::*; mod adx; pub use self::adx::*; + +mod bt; +pub use self::bt::*; diff --git a/crates/stdsimd-verify/tests/x86-intel.rs b/crates/stdsimd-verify/tests/x86-intel.rs index 29995454ea..5645bd93d6 100644 --- a/crates/stdsimd-verify/tests/x86-intel.rs +++ b/crates/stdsimd-verify/tests/x86-intel.rs @@ -246,6 +246,15 @@ fn matches(rust: &Function, intel: &Intrinsic) -> Result<(), String> { // the `x` inside the name which requires adx "_addcarry_u32" | "_addcarry_u64" | "_subborrow_u32" | "_subborrow_u64" => {} + "_bittest" + | "_bittestandset" + | "_bittestandreset" + | "_bittestandcomplement" + | "_bittest64" + | "_bittestandset64" + | "_bittestandreset64" + | "_bittestandcomplement64" => {} + _ => { if intel.cpuid.is_empty() { bail!("missing cpuid for {}", rust.name); @@ -417,6 +426,7 @@ fn equate(t: &Type, intel: &str, intrinsic: &str, is_const: bool) -> Result<(), (&Type::Ptr(&Type::PrimFloat(32)), "float*") => {} (&Type::Ptr(&Type::PrimFloat(64)), "double*") => {} (&Type::Ptr(&Type::PrimSigned(32)), "int*") => {} + (&Type::Ptr(&Type::PrimSigned(32)), "__int32*") => {} (&Type::Ptr(&Type::PrimSigned(64)), "__int64*") => {} (&Type::Ptr(&Type::PrimSigned(8)), "char*") => {} (&Type::Ptr(&Type::PrimUnsigned(16)), "unsigned short*") => {}