Skip to content

Commit 2fa62b9

Browse files
Merge pull request rust-lang#98 from rust-lang/feature/common-shuffles
Add some common shuffles
2 parents b2e25bc + 7028a58 commit 2fa62b9

File tree

2 files changed

+129
-0
lines changed

2 files changed

+129
-0
lines changed

Diff for: crates/core_simd/src/permute.rs

+109
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,115 @@ macro_rules! impl_shuffle_lane {
1313
pub fn shuffle<const IDX: [u32; $n]>(self, second: Self) -> Self {
1414
unsafe { crate::intrinsics::$fn(self, second, IDX) }
1515
}
16+
17+
/// Reverse the order of the lanes in the vector.
18+
#[inline]
19+
pub fn reverse(self) -> Self {
20+
const fn idx() -> [u32; $n] {
21+
let mut idx = [0u32; $n];
22+
let mut i = 0;
23+
while i < $n {
24+
idx[i] = ($n - i - 1) as u32;
25+
i += 1;
26+
}
27+
idx
28+
}
29+
self.shuffle::<{ idx() }>(self)
30+
}
31+
32+
/// Interleave two vectors.
33+
///
34+
/// Produces two vectors with lanes taken alternately from `self` and `other`.
35+
///
36+
/// The first result contains the first `LANES / 2` lanes from `self` and `other`,
37+
/// alternating, starting with the first lane of `self`.
38+
///
39+
/// The second result contains the last `LANES / 2` lanes from `self` and `other`,
40+
/// alternating, starting with the lane `LANES / 2` from the start of `self`.
41+
///
42+
/// This particular permutation is efficient on many architectures.
43+
///
44+
/// ```
45+
/// # use core_simd::SimdU32;
46+
/// let a = SimdU32::from_array([0, 1, 2, 3]);
47+
/// let b = SimdU32::from_array([4, 5, 6, 7]);
48+
/// let (x, y) = a.interleave(b);
49+
/// assert_eq!(x.to_array(), [0, 4, 1, 5]);
50+
/// assert_eq!(y.to_array(), [2, 6, 3, 7]);
51+
/// ```
52+
#[inline]
53+
pub fn interleave(self, other: Self) -> (Self, Self) {
54+
const fn lo() -> [u32; $n] {
55+
let mut idx = [0u32; $n];
56+
let mut i = 0;
57+
while i < $n {
58+
let offset = i / 2;
59+
idx[i] = if i % 2 == 0 {
60+
offset
61+
} else {
62+
$n + offset
63+
} as u32;
64+
i += 1;
65+
}
66+
idx
67+
}
68+
const fn hi() -> [u32; $n] {
69+
let mut idx = [0u32; $n];
70+
let mut i = 0;
71+
while i < $n {
72+
let offset = ($n + i) / 2;
73+
idx[i] = if i % 2 == 0 {
74+
offset
75+
} else {
76+
$n + offset
77+
} as u32;
78+
i += 1;
79+
}
80+
idx
81+
}
82+
(self.shuffle::<{ lo() }>(other), self.shuffle::<{ hi() }>(other))
83+
}
84+
85+
/// Deinterleave two vectors.
86+
///
87+
/// The first result takes every other lane of `self` and then `other`, starting with
88+
/// the first lane.
89+
///
90+
/// The second result takes every other lane of `self` and then `other`, starting with
91+
/// the second lane.
92+
///
93+
/// This particular permutation is efficient on many architectures.
94+
///
95+
/// ```
96+
/// # use core_simd::SimdU32;
97+
/// let a = SimdU32::from_array([0, 4, 1, 5]);
98+
/// let b = SimdU32::from_array([2, 6, 3, 7]);
99+
/// let (x, y) = a.deinterleave(b);
100+
/// assert_eq!(x.to_array(), [0, 1, 2, 3]);
101+
/// assert_eq!(y.to_array(), [4, 5, 6, 7]);
102+
/// ```
103+
#[inline]
104+
pub fn deinterleave(self, other: Self) -> (Self, Self) {
105+
const fn even() -> [u32; $n] {
106+
let mut idx = [0u32; $n];
107+
let mut i = 0;
108+
while i < $n {
109+
idx[i] = 2 * i as u32;
110+
i += 1;
111+
}
112+
idx
113+
}
114+
const fn odd() -> [u32; $n] {
115+
let mut idx = [0u32; $n];
116+
let mut i = 0;
117+
while i < $n {
118+
idx[i] = 1 + 2 * i as u32;
119+
i += 1;
120+
}
121+
idx
122+
}
123+
(self.shuffle::<{ even() }>(other), self.shuffle::<{ odd() }>(other))
124+
}
16125
}
17126
}
18127
}

Diff for: crates/core_simd/tests/permute.rs

+20
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,23 @@ fn simple_shuffle() {
1313
let b = a;
1414
assert_eq!(a.shuffle::<{ [3, 1, 4, 6] }>(b).to_array(), [9, 4, 2, 1]);
1515
}
16+
17+
#[test]
18+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
19+
fn reverse() {
20+
let a = SimdU32::from_array([0, 1, 2, 3, 4, 5, 6, 7]);
21+
assert_eq!(a.reverse().to_array(), [7, 6, 5, 4, 3, 2, 1, 0]);
22+
}
23+
24+
#[test]
25+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
26+
fn interleave() {
27+
let a = SimdU32::from_array([0, 1, 2, 3, 4, 5, 6, 7]);
28+
let b = SimdU32::from_array([8, 9, 10, 11, 12, 13, 14, 15]);
29+
let (lo, hi) = a.interleave(b);
30+
assert_eq!(lo.to_array(), [0, 8, 1, 9, 2, 10, 3, 11]);
31+
assert_eq!(hi.to_array(), [4, 12, 5, 13, 6, 14, 7, 15]);
32+
let (even, odd) = lo.deinterleave(hi);
33+
assert_eq!(even, a);
34+
assert_eq!(odd, b);
35+
}

0 commit comments

Comments
 (0)