1 use crate::simd::intrinsics;
2 use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
4 /// Constructs a new vector by selecting values from the lanes of the source vector or vectors to use.
6 /// When swizzling one vector, the indices of the result vector are indicated by a `const` array
7 /// of `usize`, like [`Swizzle`].
8 /// When swizzling two vectors, the indices are indicated by a `const` array of [`Which`], like
12 /// ## One source vector
14 /// # #![feature(portable_simd)]
15 /// # #[cfg(feature = "std")] use core_simd::{Simd, simd_swizzle};
16 /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, simd_swizzle};
17 /// let v = Simd::<f32, 4>::from_array([0., 1., 2., 3.]);
19 /// // Keeping the same size
20 /// let r = simd_swizzle!(v, [3, 0, 1, 2]);
21 /// assert_eq!(r.to_array(), [3., 0., 1., 2.]);
23 /// // Changing the number of lanes
24 /// let r = simd_swizzle!(v, [3, 1]);
25 /// assert_eq!(r.to_array(), [3., 1.]);
28 /// ## Two source vectors
30 /// # #![feature(portable_simd)]
31 /// # #[cfg(feature = "std")] use core_simd::{Simd, simd_swizzle, Which};
32 /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, simd_swizzle, Which};
34 /// let a = Simd::<f32, 4>::from_array([0., 1., 2., 3.]);
35 /// let b = Simd::<f32, 4>::from_array([4., 5., 6., 7.]);
37 /// // Keeping the same size
38 /// let r = simd_swizzle!(a, b, [First(0), First(1), Second(2), Second(3)]);
39 /// assert_eq!(r.to_array(), [0., 1., 6., 7.]);
41 /// // Changing the number of lanes
42 /// let r = simd_swizzle!(a, b, [First(0), Second(0)]);
43 /// assert_eq!(r.to_array(), [0., 4.]);
45 #[allow(unused_macros)]
46 pub macro simd_swizzle {
48 $vector:expr, $index:expr $(,)?
51 use $crate::simd::Swizzle;
53 impl<const LANES: usize> Swizzle<LANES, {$index.len()}> for Impl {
54 const INDEX: [usize; {$index.len()}] = $index;
56 Impl::swizzle($vector)
60 $first:expr, $second:expr, $index:expr $(,)?
63 use $crate::simd::{Which, Swizzle2};
65 impl<const LANES: usize> Swizzle2<LANES, {$index.len()}> for Impl {
66 const INDEX: [Which; {$index.len()}] = $index;
68 Impl::swizzle2($first, $second)
73 /// An index into one of two vectors.
74 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
76 /// Indexes the first vector.
78 /// Indexes the second vector.
82 /// Create a vector from the elements of another vector.
83 pub trait Swizzle<const INPUT_LANES: usize, const OUTPUT_LANES: usize> {
84 /// Map from the lanes of the input vector to the output vector.
85 const INDEX: [usize; OUTPUT_LANES];
87 /// Create a new vector from the lanes of `vector`.
89 /// Lane `i` of the output is `vector[Self::INDEX[i]]`.
91 #[must_use = "method returns a new vector and does not mutate the original inputs"]
92 fn swizzle<T>(vector: Simd<T, INPUT_LANES>) -> Simd<T, OUTPUT_LANES>
95 LaneCount<INPUT_LANES>: SupportedLaneCount,
96 LaneCount<OUTPUT_LANES>: SupportedLaneCount,
98 unsafe { intrinsics::simd_shuffle(vector, vector, Self::INDEX_IMPL) }
102 /// Create a vector from the elements of two other vectors.
103 pub trait Swizzle2<const INPUT_LANES: usize, const OUTPUT_LANES: usize> {
104 /// Map from the lanes of the input vectors to the output vector
105 const INDEX: [Which; OUTPUT_LANES];
107 /// Create a new vector from the lanes of `first` and `second`.
109 /// Lane `i` is `first[j]` when `Self::INDEX[i]` is `First(j)`, or `second[j]` when it is
112 #[must_use = "method returns a new vector and does not mutate the original inputs"]
114 first: Simd<T, INPUT_LANES>,
115 second: Simd<T, INPUT_LANES>,
116 ) -> Simd<T, OUTPUT_LANES>
119 LaneCount<INPUT_LANES>: SupportedLaneCount,
120 LaneCount<OUTPUT_LANES>: SupportedLaneCount,
122 unsafe { intrinsics::simd_shuffle(first, second, Self::INDEX_IMPL) }
126 /// The `simd_shuffle` intrinsic expects `u32`, so do error checking and conversion here.
127 /// This trait hides `INDEX_IMPL` from the public API.
128 trait SwizzleImpl<const INPUT_LANES: usize, const OUTPUT_LANES: usize> {
129 const INDEX_IMPL: [u32; OUTPUT_LANES];
132 impl<T, const INPUT_LANES: usize, const OUTPUT_LANES: usize> SwizzleImpl<INPUT_LANES, OUTPUT_LANES>
135 T: Swizzle<INPUT_LANES, OUTPUT_LANES> + ?Sized,
137 const INDEX_IMPL: [u32; OUTPUT_LANES] = {
138 let mut output = [0; OUTPUT_LANES];
140 while i < OUTPUT_LANES {
141 let index = Self::INDEX[i];
142 assert!(index as u32 as usize == index);
143 assert!(index < INPUT_LANES, "source lane exceeds input lane count",);
144 output[i] = index as u32;
151 /// The `simd_shuffle` intrinsic expects `u32`, so do error checking and conversion here.
152 /// This trait hides `INDEX_IMPL` from the public API.
153 trait Swizzle2Impl<const INPUT_LANES: usize, const OUTPUT_LANES: usize> {
154 const INDEX_IMPL: [u32; OUTPUT_LANES];
157 impl<T, const INPUT_LANES: usize, const OUTPUT_LANES: usize> Swizzle2Impl<INPUT_LANES, OUTPUT_LANES>
160 T: Swizzle2<INPUT_LANES, OUTPUT_LANES> + ?Sized,
162 const INDEX_IMPL: [u32; OUTPUT_LANES] = {
163 let mut output = [0; OUTPUT_LANES];
165 while i < OUTPUT_LANES {
166 let (offset, index) = match Self::INDEX[i] {
167 Which::First(index) => (false, index),
168 Which::Second(index) => (true, index),
170 assert!(index < INPUT_LANES, "source lane exceeds input lane count",);
172 // lanes are indexed by the first vector, then second vector
173 let index = if offset { index + INPUT_LANES } else { index };
174 assert!(index as u32 as usize == index);
175 output[i] = index as u32;
182 impl<T, const LANES: usize> Simd<T, LANES>
185 LaneCount<LANES>: SupportedLaneCount,
187 /// Reverse the order of the lanes in the vector.
189 #[must_use = "method returns a new vector and does not mutate the original inputs"]
190 pub fn reverse(self) -> Self {
191 const fn reverse_index<const LANES: usize>() -> [usize; LANES] {
192 let mut index = [0; LANES];
195 index[i] = LANES - i - 1;
203 impl<const LANES: usize> Swizzle<LANES, LANES> for Reverse {
204 const INDEX: [usize; LANES] = reverse_index::<LANES>();
207 Reverse::swizzle(self)
210 /// Rotates the vector such that the first `OFFSET` elements of the slice move to the end
211 /// while the last `LANES - OFFSET` elements move to the front. After calling `rotate_lanes_left`,
212 /// the element previously in lane `OFFSET` will become the first element in the slice.
214 #[must_use = "method returns a new vector and does not mutate the original inputs"]
215 pub fn rotate_lanes_left<const OFFSET: usize>(self) -> Self {
216 const fn rotate_index<const OFFSET: usize, const LANES: usize>() -> [usize; LANES] {
217 let offset = OFFSET % LANES;
218 let mut index = [0; LANES];
221 index[i] = (i + offset) % LANES;
227 struct Rotate<const OFFSET: usize>;
229 impl<const OFFSET: usize, const LANES: usize> Swizzle<LANES, LANES> for Rotate<OFFSET> {
230 const INDEX: [usize; LANES] = rotate_index::<OFFSET, LANES>();
233 Rotate::<OFFSET>::swizzle(self)
236 /// Rotates the vector such that the first `LANES - OFFSET` elements of the vector move to
237 /// the end while the last `OFFSET` elements move to the front. After calling `rotate_lanes_right`,
238 /// the element previously at index `LANES - OFFSET` will become the first element in the slice.
240 #[must_use = "method returns a new vector and does not mutate the original inputs"]
241 pub fn rotate_lanes_right<const OFFSET: usize>(self) -> Self {
242 const fn rotate_index<const OFFSET: usize, const LANES: usize>() -> [usize; LANES] {
243 let offset = LANES - OFFSET % LANES;
244 let mut index = [0; LANES];
247 index[i] = (i + offset) % LANES;
253 struct Rotate<const OFFSET: usize>;
255 impl<const OFFSET: usize, const LANES: usize> Swizzle<LANES, LANES> for Rotate<OFFSET> {
256 const INDEX: [usize; LANES] = rotate_index::<OFFSET, LANES>();
259 Rotate::<OFFSET>::swizzle(self)
262 /// Interleave two vectors.
264 /// Produces two vectors with lanes taken alternately from `self` and `other`.
266 /// The first result contains the first `LANES / 2` lanes from `self` and `other`,
267 /// alternating, starting with the first lane of `self`.
269 /// The second result contains the last `LANES / 2` lanes from `self` and `other`,
270 /// alternating, starting with the lane `LANES / 2` from the start of `self`.
273 /// #![feature(portable_simd)]
274 /// # #[cfg(feature = "std")] use core_simd::Simd;
275 /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
276 /// let a = Simd::from_array([0, 1, 2, 3]);
277 /// let b = Simd::from_array([4, 5, 6, 7]);
278 /// let (x, y) = a.interleave(b);
279 /// assert_eq!(x.to_array(), [0, 4, 1, 5]);
280 /// assert_eq!(y.to_array(), [2, 6, 3, 7]);
283 #[must_use = "method returns a new vector and does not mutate the original inputs"]
284 pub fn interleave(self, other: Self) -> (Self, Self) {
285 const fn lo<const LANES: usize>() -> [Which; LANES] {
286 let mut idx = [Which::First(0); LANES];
290 idx[i] = if i % 2 == 0 {
293 Which::Second(offset)
299 const fn hi<const LANES: usize>() -> [Which; LANES] {
300 let mut idx = [Which::First(0); LANES];
303 let offset = (LANES + i) / 2;
304 idx[i] = if i % 2 == 0 {
307 Which::Second(offset)
317 impl<const LANES: usize> Swizzle2<LANES, LANES> for Lo {
318 const INDEX: [Which; LANES] = lo::<LANES>();
321 impl<const LANES: usize> Swizzle2<LANES, LANES> for Hi {
322 const INDEX: [Which; LANES] = hi::<LANES>();
325 (Lo::swizzle2(self, other), Hi::swizzle2(self, other))
328 /// Deinterleave two vectors.
330 /// The first result takes every other lane of `self` and then `other`, starting with
333 /// The second result takes every other lane of `self` and then `other`, starting with
337 /// #![feature(portable_simd)]
338 /// # #[cfg(feature = "std")] use core_simd::Simd;
339 /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
340 /// let a = Simd::from_array([0, 4, 1, 5]);
341 /// let b = Simd::from_array([2, 6, 3, 7]);
342 /// let (x, y) = a.deinterleave(b);
343 /// assert_eq!(x.to_array(), [0, 1, 2, 3]);
344 /// assert_eq!(y.to_array(), [4, 5, 6, 7]);
347 #[must_use = "method returns a new vector and does not mutate the original inputs"]
348 pub fn deinterleave(self, other: Self) -> (Self, Self) {
349 const fn even<const LANES: usize>() -> [Which; LANES] {
350 let mut idx = [Which::First(0); LANES];
352 while i < LANES / 2 {
353 idx[i] = Which::First(2 * i);
354 idx[i + LANES / 2] = Which::Second(2 * i);
359 const fn odd<const LANES: usize>() -> [Which; LANES] {
360 let mut idx = [Which::First(0); LANES];
362 while i < LANES / 2 {
363 idx[i] = Which::First(2 * i + 1);
364 idx[i + LANES / 2] = Which::Second(2 * i + 1);
373 impl<const LANES: usize> Swizzle2<LANES, LANES> for Even {
374 const INDEX: [Which; LANES] = even::<LANES>();
377 impl<const LANES: usize> Swizzle2<LANES, LANES> for Odd {
378 const INDEX: [Which; LANES] = odd::<LANES>();
381 (Even::swizzle2(self, other), Odd::swizzle2(self, other))