#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::*;
#[inline]
#[target_feature(enable = "bmi2")]
#[cfg(target_arch = "x86_64")]
pub unsafe fn pext_u64(src: u64, mask: u64) -> u64 {
_pext_u64(src, mask)
}
#[inline]
#[target_feature(enable = "bmi2")]
#[cfg(target_arch = "x86_64")]
pub unsafe fn pdep_u64(src: u64, mask: u64) -> u64 {
_pdep_u64(src, mask)
}
#[cfg(all(target_arch = "x86_64", test))]
pub fn has_fast_bmi2() -> bool {
if !is_x86_feature_detected!("bmi2") {
return false;
}
if is_x86_feature_detected!("avx512f") {
return true;
}
true }
#[inline]
pub fn pext_u64_fallback(src: u64, mask: u64) -> u64 {
let mut result = 0u64;
let mut result_pos = 0;
for i in 0..64 {
if (mask & (1u64 << i)) != 0 {
if (src & (1u64 << i)) != 0 {
result |= 1u64 << result_pos;
}
result_pos += 1;
}
}
result
}
#[inline]
pub fn pdep_u64_fallback(src: u64, mask: u64) -> u64 {
let mut result = 0u64;
let mut src_pos = 0;
for i in 0..64 {
if (mask & (1u64 << i)) != 0 {
if (src & (1u64 << src_pos)) != 0 {
result |= 1u64 << i;
}
src_pos += 1;
}
}
result
}
#[cfg(all(test, target_arch = "x86_64"))]
mod tests {
use super::*;
#[test]
fn test_pext_fallback() {
let src = 0b11010110u64;
let mask = 0b11001100u64;
let expected = 13u64;
assert_eq!(pext_u64_fallback(src, mask), expected);
}
#[test]
fn test_pdep_fallback() {
let src = 0b1011u64; let mask = 0b11001100u64; let expected = 140u64;
assert_eq!(pdep_u64_fallback(src, mask), expected);
}
#[test]
fn test_pext_pdep_roundtrip_fallback() {
let src = 0b10110011u64;
let mask = 0b11110000u64;
let extracted = pext_u64_fallback(src, mask);
let deposited = pdep_u64_fallback(extracted, mask);
assert_eq!(deposited, src & mask);
}
#[test]
fn test_pext_hardware() {
if !is_x86_feature_detected!("bmi2") {
return;
}
let src = 0b11010110u64;
let mask = 0b11001100u64;
let expected = 13u64;
unsafe {
assert_eq!(pext_u64(src, mask), expected);
}
}
#[test]
fn test_pdep_hardware() {
if !is_x86_feature_detected!("bmi2") {
return;
}
let src = 0b1011u64;
let mask = 0b11001100u64;
let expected = 140u64;
unsafe {
assert_eq!(pdep_u64(src, mask), expected);
}
}
#[test]
fn test_pext_hardware_matches_fallback() {
if !is_x86_feature_detected!("bmi2") {
return;
}
let test_cases = [
(0b11010110u64, 0b11001100u64),
(0xFFFFFFFFu64, 0x0F0F0F0Fu64),
(0x123456789ABCDEFu64, 0xF0F0F0F0F0F0F0Fu64),
];
for (src, mask) in test_cases {
unsafe {
assert_eq!(
pext_u64(src, mask),
pext_u64_fallback(src, mask),
"PEXT mismatch for src={:#x}, mask={:#x}",
src,
mask
);
}
}
}
#[test]
fn test_pdep_hardware_matches_fallback() {
if !is_x86_feature_detected!("bmi2") {
return;
}
let test_cases = [
(0b1011u64, 0b11001100u64),
(0xFFFFu64, 0x0F0F0F0Fu64),
(0x123456u64, 0xF0F0F0F0u64),
];
for (src, mask) in test_cases {
unsafe {
assert_eq!(
pdep_u64(src, mask),
pdep_u64_fallback(src, mask),
"PDEP mismatch for src={:#x}, mask={:#x}",
src,
mask
);
}
}
}
#[test]
fn test_has_fast_bmi2_detection() {
let _ = has_fast_bmi2();
}
}