|
2 | 2 |
|
3 | 3 | use super::MaskElement;
|
4 | 4 | use crate::simd::intrinsics;
|
5 |
| -use crate::simd::{LaneCount, Simd, SupportedLaneCount}; |
| 5 | +use crate::simd::{LaneCount, Simd, SupportedLaneCount, ToBitMask}; |
6 | 6 |
|
7 | 7 | #[repr(transparent)]
|
8 | 8 | pub struct Mask<T, const LANES: usize>(Simd<T, LANES>)
|
|
66 | 66 | }
|
67 | 67 | }
|
68 | 68 |
|
| 69 | +// Used for bitmask bit order workaround |
| 70 | +pub(crate) trait ReverseBits { |
| 71 | + fn reverse_bits(self) -> Self; |
| 72 | +} |
| 73 | + |
| 74 | +macro_rules! impl_reverse_bits { |
| 75 | + { $($int:ty),* } => { |
| 76 | + $( |
| 77 | + impl ReverseBits for $int { |
| 78 | + fn reverse_bits(self) -> Self { <$int>::reverse_bits(self) } |
| 79 | + } |
| 80 | + )* |
| 81 | + } |
| 82 | +} |
| 83 | + |
| 84 | +impl_reverse_bits! { u8, u16, u32, u64 } |
| 85 | + |
69 | 86 | impl<T, const LANES: usize> Mask<T, LANES>
|
70 | 87 | where
|
71 | 88 | T: MaskElement,
|
@@ -110,41 +127,36 @@ where
|
110 | 127 | unsafe { Mask(intrinsics::simd_cast(self.0)) }
|
111 | 128 | }
|
112 | 129 |
|
113 |
| - #[cfg(feature = "generic_const_exprs")] |
114 | 130 | #[inline]
|
115 |
| - #[must_use = "method returns a new array and does not mutate the original value"] |
116 |
| - pub fn to_bitmask(self) -> [u8; LaneCount::<LANES>::BITMASK_LEN] { |
117 |
| - unsafe { |
118 |
| - let mut bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN] = |
119 |
| - intrinsics::simd_bitmask(self.0); |
120 |
| - |
121 |
| - // There is a bug where LLVM appears to implement this operation with the wrong |
122 |
| - // bit order. |
123 |
| - // TODO fix this in a better way |
124 |
| - if cfg!(target_endian = "big") { |
125 |
| - for x in bitmask.as_mut() { |
126 |
| - *x = x.reverse_bits(); |
127 |
| - } |
128 |
| - } |
| 131 | + pub(crate) fn to_bitmask_integer<U: ReverseBits>(self) -> U |
| 132 | + where |
| 133 | + super::Mask<T, LANES>: ToBitMask<BitMask = U>, |
| 134 | + { |
| 135 | + // Safety: U is required to be the appropriate bitmask type |
| 136 | + let bitmask: U = unsafe { intrinsics::simd_bitmask(self.0) }; |
129 | 137 |
|
| 138 | + // LLVM assumes bit order should match endianness |
| 139 | + if cfg!(target_endian = "big") { |
| 140 | + bitmask.reverse_bits() |
| 141 | + } else { |
130 | 142 | bitmask
|
131 | 143 | }
|
132 | 144 | }
|
133 | 145 |
|
134 |
| - #[cfg(feature = "generic_const_exprs")] |
135 | 146 | #[inline]
|
136 |
| - #[must_use = "method returns a new mask and does not mutate the original value"] |
137 |
| - pub fn from_bitmask(mut bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN]) -> Self { |
138 |
| - unsafe { |
139 |
| - // There is a bug where LLVM appears to implement this operation with the wrong |
140 |
| - // bit order. |
141 |
| - // TODO fix this in a better way |
142 |
| - if cfg!(target_endian = "big") { |
143 |
| - for x in bitmask.as_mut() { |
144 |
| - *x = x.reverse_bits(); |
145 |
| - } |
146 |
| - } |
| 147 | + pub(crate) fn from_bitmask_integer<U: ReverseBits>(bitmask: U) -> Self |
| 148 | + where |
| 149 | + super::Mask<T, LANES>: ToBitMask<BitMask = U>, |
| 150 | + { |
| 151 | + // LLVM assumes bit order should match endianness |
| 152 | + let bitmask = if cfg!(target_endian = "big") { |
| 153 | + bitmask.reverse_bits() |
| 154 | + } else { |
| 155 | + bitmask |
| 156 | + }; |
147 | 157 |
|
| 158 | + // Safety: U is required to be the appropriate bitmask type |
| 159 | + unsafe { |
148 | 160 | Self::from_int_unchecked(intrinsics::simd_select_bitmask(
|
149 | 161 | bitmask,
|
150 | 162 | Self::splat(true).to_int(),
|
|
0 commit comments