about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCaleb Zulawski <caleb.zulawski@gmail.com>2021-06-21 17:05:43 -0400
committerGitHub <noreply@github.com>2021-06-21 14:05:43 -0700
commit15b4e280049a2b495635027ebfcb3b6930fbc12a (patch)
treecb6d38b90c600e0faf9ff5083b378858d20552b0
parent57e67c905fe9fb3d45a1714d25baa5dfc143299c (diff)
downloadrust-15b4e280049a2b495635027ebfcb3b6930fbc12a.tar.gz
rust-15b4e280049a2b495635027ebfcb3b6930fbc12a.zip
Add from_bitmask (#136)
* Add from_bitmask
* Add mips workaround
-rw-r--r--crates/core_simd/src/masks/bitmask.rs9
-rw-r--r--crates/core_simd/src/masks/full_masks.rs24
-rw-r--r--crates/core_simd/src/masks/mod.rs5
-rw-r--r--crates/core_simd/tests/masks.rs6
4 files changed, 42 insertions, 2 deletions
diff --git a/crates/core_simd/src/masks/bitmask.rs b/crates/core_simd/src/masks/bitmask.rs
index 31c7f6e7c28..fab136d2b24 100644
--- a/crates/core_simd/src/masks/bitmask.rs
+++ b/crates/core_simd/src/masks/bitmask.rs
@@ -101,6 +101,15 @@ impl<T: Mask, const LANES: usize> BitMask<T, LANES> {
     }
 
     #[inline]
+    pub fn from_bitmask<U: Mask>(bitmask: U::BitMask) -> Self {
+        assert_eq!(
+            core::mem::size_of::<T::BitMask>(),
+            core::mem::size_of::<U::BitMask>()
+        );
+        unsafe { core::mem::transmute_copy(&bitmask) }
+    }
+
+    #[inline]
     pub fn any(self) -> bool {
         self != Self::splat(false)
     }
diff --git a/crates/core_simd/src/masks/full_masks.rs b/crates/core_simd/src/masks/full_masks.rs
index c2bfa03dfc6..7d98333ef60 100644
--- a/crates/core_simd/src/masks/full_masks.rs
+++ b/crates/core_simd/src/masks/full_masks.rs
@@ -126,6 +126,30 @@ macro_rules! define_mask {
                     bitmask
                 }
             }
+
+            #[inline]
+            pub fn from_bitmask<U: crate::Mask>(mut bitmask: U::BitMask) -> Self {
+                unsafe {
+                    // There is a bug where LLVM appears to implement this operation with the wrong
+                    // bit order.
+                    // TODO fix this in a better way
+                    if cfg!(any(target_arch = "mips", target_arch = "mips64")) {
+                        for x in bitmask.as_mut() {
+                            *x = x.reverse_bits();
+                        }
+                    }
+
+                    // TODO remove the transmute when rustc is more flexible
+                    assert_eq!(core::mem::size_of::<U::IntBitMask>(), core::mem::size_of::<U::BitMask>());
+                    let bitmask: U::IntBitMask = core::mem::transmute_copy(&bitmask);
+
+                    Self::from_int_unchecked(crate::intrinsics::simd_select_bitmask(
+                        bitmask,
+                        Self::splat(true).to_int(),
+                        Self::splat(false).to_int(),
+                    ))
+                }
+            }
         }
 
         impl<T: Mask, const LANES: usize> core::convert::From<$name<T, LANES>> for crate::$type<LANES>
diff --git a/crates/core_simd/src/masks/mod.rs b/crates/core_simd/src/masks/mod.rs
index 81a410de200..1d6b2e45224 100644
--- a/crates/core_simd/src/masks/mod.rs
+++ b/crates/core_simd/src/masks/mod.rs
@@ -178,6 +178,11 @@ macro_rules! define_opaque_mask {
             pub fn to_bitmask(self) -> <Self as Mask>::BitMask {
                 self.0.to_bitmask::<Self>()
             }
+
+            /// Convert a bitmask to a mask.
+            pub fn from_bitmask(bitmask: <Self as Mask>::BitMask) -> Self {
+                Self(<$inner_ty>::from_bitmask::<Self>(bitmask))
+            }
         }
 
         // vector/array conversion
diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs
index 5c2e60dd7c8..32dea49729f 100644
--- a/crates/core_simd/tests/masks.rs
+++ b/crates/core_simd/tests/masks.rs
@@ -67,13 +67,15 @@ macro_rules! test_mask_api {
             }
 
             #[test]
-            fn to_bitmask() {
+            fn roundtrip_bitmask_conversion() {
                 let values = [
                     true, false, false, true, false, false, true, false,
                     true, true, false, false, false, false, false, true,
                 ];
                 let mask = core_simd::$name::<16>::from_array(values);
-                assert_eq!(mask.to_bitmask(), [0b01001001, 0b10000011]);
+                let bitmask = mask.to_bitmask();
+                assert_eq!(bitmask, [0b01001001, 0b10000011]);
+                assert_eq!(core_simd::$name::<16>::from_bitmask(bitmask), mask);
             }
         }
     }