From 3183afb6b5fcbf688bb90cf1db3f635406f868dc Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Fri, 29 Jul 2022 11:57:05 -0400 Subject: [PATCH 1/5] Fix interleave/deinterleave for vectors with only one lane --- crates/core_simd/src/swizzle.rs | 12 ++++++++++-- crates/core_simd/tests/swizzle.rs | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/crates/core_simd/src/swizzle.rs b/crates/core_simd/src/swizzle.rs index 22999d24950f..02567252a637 100644 --- a/crates/core_simd/src/swizzle.rs +++ b/crates/core_simd/src/swizzle.rs @@ -325,7 +325,11 @@ where const INDEX: [Which; LANES] = hi::(); } - (Lo::swizzle2(self, other), Hi::swizzle2(self, other)) + if LANES == 1 { + (self, other) + } else { + (Lo::swizzle2(self, other), Hi::swizzle2(self, other)) + } } /// Deinterleave two vectors. @@ -380,6 +384,10 @@ where const INDEX: [Which; LANES] = odd::(); } - (Even::swizzle2(self, other), Odd::swizzle2(self, other)) + if LANES == 1 { + (self, other) + } else { + (Even::swizzle2(self, other), Odd::swizzle2(self, other)) + } } } diff --git a/crates/core_simd/tests/swizzle.rs b/crates/core_simd/tests/swizzle.rs index 51c63611aba6..33a7becb4212 100644 --- a/crates/core_simd/tests/swizzle.rs +++ b/crates/core_simd/tests/swizzle.rs @@ -60,3 +60,17 @@ fn interleave() { assert_eq!(even, a); assert_eq!(odd, b); } + +// portable-simd#298 +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn interleave_one() { + let a = Simd::from_array([0]); + let b = Simd::from_array([1]); + let (lo, hi) = a.interleave(b); + assert_eq!(lo.to_array(), [0]); + assert_eq!(hi.to_array(), [1]); + let (even, odd) = lo.deinterleave(hi); + assert_eq!(even, a); + assert_eq!(odd, b); +} From 6bf512823548b4fdbb7127489e883bff8a98b33f Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Mon, 1 Aug 2022 00:34:58 -0400 Subject: [PATCH 2/5] Simplify interleave/deinterleave and fix for odd-length vectors. --- crates/core_simd/src/swizzle.rs | 74 ++++++++++++--------------------- 1 file changed, 26 insertions(+), 48 deletions(-) diff --git a/crates/core_simd/src/swizzle.rs b/crates/core_simd/src/swizzle.rs index 02567252a637..0b66b8a0ae03 100644 --- a/crates/core_simd/src/swizzle.rs +++ b/crates/core_simd/src/swizzle.rs @@ -265,13 +265,10 @@ where /// Interleave two vectors. /// - /// Produces two vectors with lanes taken alternately from `self` and `other`. + /// The resulting vectors contain lanes taken alternatively from `self` and `other`, first + /// filling the first result, and then the second. /// - /// The first result contains the first `LANES / 2` lanes from `self` and `other`, - /// alternating, starting with the first lane of `self`. - /// - /// The second result contains the last `LANES / 2` lanes from `self` and `other`, - /// alternating, starting with the lane `LANES / 2` from the start of `self`. + /// The reverse of this operation is [`Simd::deinterleave`]. /// /// ``` /// #![feature(portable_simd)] @@ -285,29 +282,17 @@ where #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] pub fn interleave(self, other: Self) -> (Self, Self) { - const fn lo() -> [Which; LANES] { + const fn interleave(high: bool) -> [Which; LANES] { let mut idx = [Which::First(0); LANES]; let mut i = 0; while i < LANES { - let offset = i / 2; - idx[i] = if i % 2 == 0 { - Which::First(offset) + // Treat the source as a concatenated vector + let dst_index = if high { i + LANES } else { i }; + let src_index = dst_index / 2 + (dst_index % 2) * LANES; + idx[i] = if src_index < LANES { + Which::First(src_index) } else { - Which::Second(offset) - }; - i += 1; - } - idx - } - const fn hi() -> [Which; LANES] { - let mut idx = [Which::First(0); LANES]; - let mut i = 0; - while i < LANES { - let offset = (LANES + i) / 2; - idx[i] = if i % 2 == 0 { - Which::First(offset) - } else { - Which::Second(offset) + Which::Second(src_index % LANES) }; i += 1; } @@ -318,18 +303,14 @@ where struct Hi; impl Swizzle2 for Lo { - const INDEX: [Which; LANES] = lo::(); + const INDEX: [Which; LANES] = interleave::(false); } impl Swizzle2 for Hi { - const INDEX: [Which; LANES] = hi::(); + const INDEX: [Which; LANES] = interleave::(true); } - if LANES == 1 { - (self, other) - } else { - (Lo::swizzle2(self, other), Hi::swizzle2(self, other)) - } + (Lo::swizzle2(self, other), Hi::swizzle2(self, other)) } /// Deinterleave two vectors. @@ -340,6 +321,8 @@ where /// The second result takes every other lane of `self` and then `other`, starting with /// the second lane. /// + /// The reverse of this operation is [`Simd::interleave`]. + /// /// ``` /// #![feature(portable_simd)] /// # use core::simd::Simd; @@ -352,22 +335,17 @@ where #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] pub fn deinterleave(self, other: Self) -> (Self, Self) { - const fn even() -> [Which; LANES] { + const fn deinterleave(second: bool) -> [Which; LANES] { let mut idx = [Which::First(0); LANES]; let mut i = 0; - while i < LANES / 2 { - idx[i] = Which::First(2 * i); - idx[i + LANES / 2] = Which::Second(2 * i); - i += 1; - } - idx - } - const fn odd() -> [Which; LANES] { - let mut idx = [Which::First(0); LANES]; - let mut i = 0; - while i < LANES / 2 { - idx[i] = Which::First(2 * i + 1); - idx[i + LANES / 2] = Which::Second(2 * i + 1); + while i < LANES { + // Treat the source as a concatenated vector + let src_index = i * 2 + if second { 1 } else { 0 }; + idx[i] = if src_index < LANES { + Which::First(src_index) + } else { + Which::Second(src_index % LANES) + }; i += 1; } idx @@ -377,11 +355,11 @@ where struct Odd; impl Swizzle2 for Even { - const INDEX: [Which; LANES] = even::(); + const INDEX: [Which; LANES] = deinterleave::(false); } impl Swizzle2 for Odd { - const INDEX: [Which; LANES] = odd::(); + const INDEX: [Which; LANES] = deinterleave::(true); } if LANES == 1 { From c739af3908613ba3f611dce115525e2f2f91bfca Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Mon, 1 Aug 2022 00:38:29 -0400 Subject: [PATCH 3/5] Hide rustc unstable feature from docs --- crates/core_simd/src/swizzle.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/core_simd/src/swizzle.rs b/crates/core_simd/src/swizzle.rs index 0b66b8a0ae03..72cce7aeb048 100644 --- a/crates/core_simd/src/swizzle.rs +++ b/crates/core_simd/src/swizzle.rs @@ -271,7 +271,7 @@ where /// The reverse of this operation is [`Simd::deinterleave`]. /// /// ``` - /// #![feature(portable_simd)] + /// # #![feature(portable_simd)] /// # use core::simd::Simd; /// let a = Simd::from_array([0, 1, 2, 3]); /// let b = Simd::from_array([4, 5, 6, 7]); @@ -324,7 +324,7 @@ where /// The reverse of this operation is [`Simd::interleave`]. /// /// ``` - /// #![feature(portable_simd)] + /// # #![feature(portable_simd)] /// # use core::simd::Simd; /// let a = Simd::from_array([0, 4, 1, 5]); /// let b = Simd::from_array([2, 6, 3, 7]); From d030301161a372b545e5d8c1784cba113e5a8ebd Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Mon, 1 Aug 2022 19:52:35 -0400 Subject: [PATCH 4/5] Remove special case for length-1 vectors --- crates/core_simd/src/swizzle.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/crates/core_simd/src/swizzle.rs b/crates/core_simd/src/swizzle.rs index 72cce7aeb048..61cc604e4cd4 100644 --- a/crates/core_simd/src/swizzle.rs +++ b/crates/core_simd/src/swizzle.rs @@ -362,10 +362,6 @@ where const INDEX: [Which; LANES] = deinterleave::(true); } - if LANES == 1 { - (self, other) - } else { - (Even::swizzle2(self, other), Odd::swizzle2(self, other)) - } + (Even::swizzle2(self, other), Odd::swizzle2(self, other)) } } From 5f7066430b9239cfe8243ddba4c29416f002ae6b Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Mon, 1 Aug 2022 19:57:41 -0400 Subject: [PATCH 5/5] Simplify expression --- crates/core_simd/src/swizzle.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/core_simd/src/swizzle.rs b/crates/core_simd/src/swizzle.rs index 61cc604e4cd4..68f20516cf5b 100644 --- a/crates/core_simd/src/swizzle.rs +++ b/crates/core_simd/src/swizzle.rs @@ -340,7 +340,7 @@ where let mut i = 0; while i < LANES { // Treat the source as a concatenated vector - let src_index = i * 2 + if second { 1 } else { 0 }; + let src_index = i * 2 + second as usize; idx[i] = if src_index < LANES { Which::First(src_index) } else {