Skip to content

Commit

Permalink
Manually implement for supported lanes
Browse files Browse the repository at this point in the history
  • Loading branch information
calebzulawski authored and workingjubilee committed Feb 25, 2022
1 parent 842ac87 commit 11c3eef
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 59 deletions.
5 changes: 3 additions & 2 deletions crates/core_simd/src/masks/bitmask.rs
Expand Up @@ -116,12 +116,13 @@ where
}

#[inline]
pub unsafe fn to_bitmask_intrinsic<U>(self) -> U {
pub unsafe fn to_bitmask_integer<U>(self) -> U {
unsafe { core::mem::transmute_copy(&self.0) }
}

// Safety: U must be the integer with the exact number of bits required to hold the bitmask for
#[inline]
pub unsafe fn from_bitmask_intrinsic<U>(bitmask: U) -> Self {
pub unsafe fn from_bitmask_integer<U>(bitmask: U) -> Self {
unsafe { Self(core::mem::transmute_copy(&bitmask), PhantomData) }
}

Expand Down
6 changes: 4 additions & 2 deletions crates/core_simd/src/masks/full_masks.rs
Expand Up @@ -110,13 +110,15 @@ where
}

#[inline]
pub unsafe fn to_bitmask_intrinsic<U>(self) -> U {
pub unsafe fn to_bitmask_integer<U>(self) -> U {
// Safety: caller must only return bitmask types
unsafe { intrinsics::simd_bitmask(self.0) }
}

// Safety: U must be the integer with the exact number of bits required to hold the bitmask for
// this mask
#[inline]
pub unsafe fn from_bitmask_intrinsic<U>(bitmask: U) -> Self {
pub unsafe fn from_bitmask_integer<U>(bitmask: U) -> Self {
// Safety: caller must only pass bitmask types
unsafe {
Self::from_int_unchecked(intrinsics::simd_select_bitmask(
Expand Down
84 changes: 30 additions & 54 deletions crates/core_simd/src/masks/to_bitmask.rs
@@ -1,78 +1,54 @@
use super::{mask_impl, Mask, MaskElement};

/// Converts masks to and from bitmasks.
/// Converts masks to and from integer bitmasks.
///
/// In a bitmask, each bit represents if the corresponding lane in the mask is set.
pub trait ToBitMask<BitMask> {
/// Each bit of the bitmask corresponds to a mask lane, starting with the LSB.
pub trait ToBitMask {
/// The integer bitmask type.
type BitMask;

/// Converts a mask to a bitmask.
fn to_bitmask(self) -> BitMask;
fn to_bitmask(self) -> Self::BitMask;

/// Converts a bitmask to a mask.
fn from_bitmask(bitmask: BitMask) -> Self;
fn from_bitmask(bitmask: Self::BitMask) -> Self;
}

macro_rules! impl_integer_intrinsic {
{ $(unsafe impl ToBitMask<$int:ty> for Mask<_, $lanes:literal>)* } => {
$(
impl<T: MaskElement> ToBitMask<$int> for Mask<T, $lanes> {
fn to_bitmask(self) -> $int {
unsafe { self.0.to_bitmask_intrinsic() }
}
/// Converts masks to and from byte array bitmasks.
///
/// Each bit of the bitmask corresponds to a mask lane, starting with the LSB of the first byte.
pub trait ToBitMaskArray {
/// The length of the bitmask array.
const BYTES: usize;

fn from_bitmask(bitmask: $int) -> Self {
unsafe { Self(mask_impl::Mask::from_bitmask_intrinsic(bitmask)) }
}
}
)*
}
}
/// Converts a mask to a bitmask.
fn to_bitmask_array(self) -> [u8; Self::BYTES];

impl_integer_intrinsic! {
unsafe impl ToBitMask<u8> for Mask<_, 8>
unsafe impl ToBitMask<u16> for Mask<_, 16>
unsafe impl ToBitMask<u32> for Mask<_, 32>
unsafe impl ToBitMask<u64> for Mask<_, 64>
/// Converts a bitmask to a mask.
fn from_bitmask_array(bitmask: [u8; Self::BYTES]) -> Self;
}

macro_rules! impl_integer_via {
{ $(impl ToBitMask<$int:ty, via $via:ty> for Mask<_, $lanes:literal>)* } => {
macro_rules! impl_integer_intrinsic {
{ $(unsafe impl ToBitMask<BitMask=$int:ty> for Mask<_, $lanes:literal>)* } => {
$(
impl<T: MaskElement> ToBitMask<$int> for Mask<T, $lanes> {
impl<T: MaskElement> ToBitMask for Mask<T, $lanes> {
type BitMask = $int;

fn to_bitmask(self) -> $int {
let bitmask: $via = self.to_bitmask();
bitmask as _
unsafe { self.0.to_bitmask_integer() }
}

fn from_bitmask(bitmask: $int) -> Self {
Self::from_bitmask(bitmask as $via)
unsafe { Self(mask_impl::Mask::from_bitmask_integer(bitmask)) }
}
}
)*
}
}

impl_integer_via! {
impl ToBitMask<u16, via u8> for Mask<_, 8>
impl ToBitMask<u32, via u8> for Mask<_, 8>
impl ToBitMask<u64, via u8> for Mask<_, 8>

impl ToBitMask<u32, via u16> for Mask<_, 16>
impl ToBitMask<u64, via u16> for Mask<_, 16>

impl ToBitMask<u64, via u32> for Mask<_, 32>
}

#[cfg(target_pointer_width = "32")]
impl_integer_via! {
impl ToBitMask<usize, via u8> for Mask<_, 8>
impl ToBitMask<usize, via u16> for Mask<_, 16>
impl ToBitMask<usize, via u32> for Mask<_, 32>
}

#[cfg(target_pointer_width = "64")]
impl_integer_via! {
impl ToBitMask<usize, via u8> for Mask<_, 8>
impl ToBitMask<usize, via u16> for Mask<_, 16>
impl ToBitMask<usize, via u32> for Mask<_, 32>
impl ToBitMask<usize, via u64> for Mask<_, 64>
impl_integer_intrinsic! {
unsafe impl ToBitMask<BitMask=u8> for Mask<_, 8>
unsafe impl ToBitMask<BitMask=u16> for Mask<_, 16>
unsafe impl ToBitMask<BitMask=u32> for Mask<_, 32>
unsafe impl ToBitMask<BitMask=u64> for Mask<_, 64>
}
2 changes: 1 addition & 1 deletion crates/core_simd/tests/masks.rs
Expand Up @@ -76,7 +76,7 @@ macro_rules! test_mask_api {
true, true, false, false, false, false, false, true,
];
let mask = core_simd::Mask::<$type, 16>::from_array(values);
let bitmask: u16 = mask.to_bitmask();
let bitmask = mask.to_bitmask();
assert_eq!(bitmask, 0b1000001101001001);
assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask);
}
Expand Down

0 comments on commit 11c3eef

Please sign in to comment.