From c7d9ad8c2cae5fcc572fe2f5ed5c88fac25c4a97 Mon Sep 17 00:00:00 2001 From: Samuel Shepard Date: Fri, 27 Sep 2024 15:07:28 -0400 Subject: [PATCH 1/6] Add shift_elements_{left,right} for Simd and Masks --- crates/core_simd/src/swizzle.rs | 74 +++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/crates/core_simd/src/swizzle.rs b/crates/core_simd/src/swizzle.rs index e0edb2cf10a..9fa6a7da8d7 100644 --- a/crates/core_simd/src/swizzle.rs +++ b/crates/core_simd/src/swizzle.rs @@ -251,6 +251,56 @@ where Rotate::::swizzle(self) } + /// Shifts the vector elements to the left by `OFFSET`, padding by the + /// default value (e.g., zero) to the right. + #[inline] + #[must_use = "method returns a new vector and does not mutate the original inputs"] + fn shift_elements_left(self) -> Self + where + T: Default, + { + struct Shift; + + impl Swizzle for Shift { + const INDEX: [usize; N] = const { + let mut index = [N; N]; + let mut i = 0; + while i + OFFSET < N { + index[i] = i + OFFSET; + i += 1; + } + index + }; + } + + Shift::::concat_swizzle(self, Self::default()) + } + + /// Shifts the vector elements to the right by `OFFSET`, padding by the + /// default value (e.g., zero) from the left. + #[inline] + #[must_use = "method returns a new vector and does not mutate the original inputs"] + fn shift_elements_right(self) -> Self + where + T: Default, + { + struct Shift; + + impl Swizzle for Shift { + const INDEX: [usize; N] = const { + let mut index = [N; N]; + let mut i = OFFSET; + while i < N { + index[i] = i - OFFSET; + i += 1; + } + index + }; + } + + Shift::::concat_swizzle(self, Self::default()) + } + /// Interleave two vectors. /// /// The resulting vectors contain elements taken alternatively from `self` and `other`, first @@ -451,6 +501,30 @@ where unsafe { Self::from_int_unchecked(self.to_int().rotate_elements_right::()) } } + /// Shifts the mask elements to the left by `OFFSET`, padding by the + /// default value (e.g., zero) to the right. + #[inline] + #[must_use = "method returns a new vector and does not mutate the original inputs"] + pub fn shift_elements_left(self) -> Self + where + T: Default, + { + // Safety: swizzles are safe for masks + unsafe { Self::from_int_unchecked(self.to_int().shift_elements_left::()) } + } + + /// Shifts the mask elements to the right by `OFFSET`, padding by the + /// default value (e.g., `false`) from the left. + #[inline] + #[must_use = "method returns a new vector and does not mutate the original inputs"] + pub fn shift_elements_right(self) -> Self + where + T: Default, + { + // Safety: swizzles are safe for masks + unsafe { Self::from_int_unchecked(self.to_int().shift_elements_right::()) } + } + /// Interleave two masks. /// /// The resulting masks contain elements taken alternatively from `self` and `other`, first From 55b4b74a120dc83317f143b8a7ce292f6afd34ea Mon Sep 17 00:00:00 2001 From: Samuel Shepard Date: Fri, 27 Sep 2024 15:12:58 -0400 Subject: [PATCH 2/6] Add tests, make public --- crates/core_simd/src/swizzle.rs | 4 ++-- crates/core_simd/tests/swizzle.rs | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/crates/core_simd/src/swizzle.rs b/crates/core_simd/src/swizzle.rs index 9fa6a7da8d7..cf1e08aa668 100644 --- a/crates/core_simd/src/swizzle.rs +++ b/crates/core_simd/src/swizzle.rs @@ -255,7 +255,7 @@ where /// default value (e.g., zero) to the right. #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] - fn shift_elements_left(self) -> Self + pub fn shift_elements_left(self) -> Self where T: Default, { @@ -280,7 +280,7 @@ where /// default value (e.g., zero) from the left. #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] - fn shift_elements_right(self) -> Self + pub fn shift_elements_right(self) -> Self where T: Default, { diff --git a/crates/core_simd/tests/swizzle.rs b/crates/core_simd/tests/swizzle.rs index 522d71439b7..98045fc5c54 100644 --- a/crates/core_simd/tests/swizzle.rs +++ b/crates/core_simd/tests/swizzle.rs @@ -48,6 +48,24 @@ fn rotate() { assert_eq!(a.rotate_elements_right::<5>().to_array(), [4, 1, 2, 3]); } +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn shift() { + let a = Simd::from_array([1, 2, 3, 4]); + assert_eq!(a.shift_elements_left::<0>().to_array(), [1, 2, 3, 4]); + assert_eq!(a.shift_elements_left::<1>().to_array(), [2, 3, 4, 0]); + assert_eq!(a.shift_elements_left::<2>().to_array(), [3, 4, 0, 0]); + assert_eq!(a.shift_elements_left::<3>().to_array(), [4, 0, 0, 0]); + assert_eq!(a.shift_elements_left::<4>().to_array(), [0, 0, 0, 0]); + assert_eq!(a.shift_elements_left::<5>().to_array(), [0, 0, 0, 0]); + assert_eq!(a.shift_elements_right::<0>().to_array(), [1, 2, 3, 4]); + assert_eq!(a.shift_elements_right::<1>().to_array(), [0, 1, 2, 3]); + assert_eq!(a.shift_elements_right::<2>().to_array(), [0, 0, 1, 2]); + assert_eq!(a.shift_elements_right::<3>().to_array(), [0, 0, 0, 1]); + assert_eq!(a.shift_elements_right::<4>().to_array(), [0, 0, 0, 0]); + assert_eq!(a.shift_elements_right::<5>().to_array(), [0, 0, 0, 0]); +} + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn interleave() { From f5fea5702863eb9ff30b42ee4e8942d9f70eea54 Mon Sep 17 00:00:00 2001 From: Samuel Shepard Date: Fri, 27 Sep 2024 19:18:30 -0400 Subject: [PATCH 3/6] Change API to accept a `padding` argument --- crates/core_simd/src/swizzle.rs | 44 +++++++++++-------------------- crates/core_simd/tests/swizzle.rs | 24 ++++++++--------- 2 files changed, 28 insertions(+), 40 deletions(-) diff --git a/crates/core_simd/src/swizzle.rs b/crates/core_simd/src/swizzle.rs index cf1e08aa668..6353196e4cf 100644 --- a/crates/core_simd/src/swizzle.rs +++ b/crates/core_simd/src/swizzle.rs @@ -251,14 +251,11 @@ where Rotate::::swizzle(self) } - /// Shifts the vector elements to the left by `OFFSET`, padding by the - /// default value (e.g., zero) to the right. + /// Shifts the vector elements to the left by `OFFSET`, filling in with + /// `padding` from the right. #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] - pub fn shift_elements_left(self) -> Self - where - T: Default, - { + pub fn shift_elements_left(self, padding: T) -> Self { struct Shift; impl Swizzle for Shift { @@ -273,17 +270,14 @@ where }; } - Shift::::concat_swizzle(self, Self::default()) + Shift::::concat_swizzle(self, Simd::splat(padding)) } - /// Shifts the vector elements to the right by `OFFSET`, padding by the - /// default value (e.g., zero) from the left. + /// Shifts the vector elements to the right by `OFFSET`, filling in with + /// `padding` from the left. #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] - pub fn shift_elements_right(self) -> Self - where - T: Default, - { + pub fn shift_elements_right(self, padding: T) -> Self { struct Shift; impl Swizzle for Shift { @@ -298,7 +292,7 @@ where }; } - Shift::::concat_swizzle(self, Self::default()) + Shift::::concat_swizzle(self, Simd::splat(padding)) } /// Interleave two vectors. @@ -501,28 +495,22 @@ where unsafe { Self::from_int_unchecked(self.to_int().rotate_elements_right::()) } } - /// Shifts the mask elements to the left by `OFFSET`, padding by the - /// default value (e.g., zero) to the right. + /// Shifts the mask elements to the left by `OFFSET`, filling in with + /// `padding` from the right. #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] - pub fn shift_elements_left(self) -> Self - where - T: Default, - { + pub fn shift_elements_left(self, padding: T) -> Self { // Safety: swizzles are safe for masks - unsafe { Self::from_int_unchecked(self.to_int().shift_elements_left::()) } + unsafe { Self::from_int_unchecked(self.to_int().shift_elements_left::(padding)) } } - /// Shifts the mask elements to the right by `OFFSET`, padding by the - /// default value (e.g., `false`) from the left. + /// Shifts the mask elements to the right by `OFFSET`, filling in with + /// `padding` from the left. #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] - pub fn shift_elements_right(self) -> Self - where - T: Default, - { + pub fn shift_elements_right(self, padding: T) -> Self { // Safety: swizzles are safe for masks - unsafe { Self::from_int_unchecked(self.to_int().shift_elements_right::()) } + unsafe { Self::from_int_unchecked(self.to_int().shift_elements_right::(padding)) } } /// Interleave two masks. diff --git a/crates/core_simd/tests/swizzle.rs b/crates/core_simd/tests/swizzle.rs index 98045fc5c54..7001e5f6bf8 100644 --- a/crates/core_simd/tests/swizzle.rs +++ b/crates/core_simd/tests/swizzle.rs @@ -52,18 +52,18 @@ fn rotate() { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn shift() { let a = Simd::from_array([1, 2, 3, 4]); - assert_eq!(a.shift_elements_left::<0>().to_array(), [1, 2, 3, 4]); - assert_eq!(a.shift_elements_left::<1>().to_array(), [2, 3, 4, 0]); - assert_eq!(a.shift_elements_left::<2>().to_array(), [3, 4, 0, 0]); - assert_eq!(a.shift_elements_left::<3>().to_array(), [4, 0, 0, 0]); - assert_eq!(a.shift_elements_left::<4>().to_array(), [0, 0, 0, 0]); - assert_eq!(a.shift_elements_left::<5>().to_array(), [0, 0, 0, 0]); - assert_eq!(a.shift_elements_right::<0>().to_array(), [1, 2, 3, 4]); - assert_eq!(a.shift_elements_right::<1>().to_array(), [0, 1, 2, 3]); - assert_eq!(a.shift_elements_right::<2>().to_array(), [0, 0, 1, 2]); - assert_eq!(a.shift_elements_right::<3>().to_array(), [0, 0, 0, 1]); - assert_eq!(a.shift_elements_right::<4>().to_array(), [0, 0, 0, 0]); - assert_eq!(a.shift_elements_right::<5>().to_array(), [0, 0, 0, 0]); + assert_eq!(a.shift_elements_left::<0>(0).to_array(), [1, 2, 3, 4]); + assert_eq!(a.shift_elements_left::<1>(0).to_array(), [2, 3, 4, 0]); + assert_eq!(a.shift_elements_left::<2>(9).to_array(), [3, 4, 9, 9]); + assert_eq!(a.shift_elements_left::<3>(8).to_array(), [4, 8, 8, 8]); + assert_eq!(a.shift_elements_left::<4>(7).to_array(), [7, 7, 7, 7]); + assert_eq!(a.shift_elements_left::<5>(6).to_array(), [6, 6, 6, 6]); + assert_eq!(a.shift_elements_right::<0>(0).to_array(), [1, 2, 3, 4]); + assert_eq!(a.shift_elements_right::<1>(0).to_array(), [0, 1, 2, 3]); + assert_eq!(a.shift_elements_right::<2>(-1).to_array(), [-1, -1, 1, 2]); + assert_eq!(a.shift_elements_right::<3>(-2).to_array(), [-2, -2, -2, 1]); + assert_eq!(a.shift_elements_right::<4>(-3).to_array(), [-3, -3, -3, -3]); + assert_eq!(a.shift_elements_right::<5>(-4).to_array(), [-4, -4, -4, -4]); } #[test] From 8cff838daa3274c0c4f9bbef67c46587033e267d Mon Sep 17 00:00:00 2001 From: Sam Shepard Date: Fri, 27 Sep 2024 21:04:49 -0400 Subject: [PATCH 4/6] Update crates/core_simd/src/swizzle.rs Co-authored-by: Caleb Zulawski --- 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 6353196e4cf..a7833ea92c0 100644 --- a/crates/core_simd/src/swizzle.rs +++ b/crates/core_simd/src/swizzle.rs @@ -498,7 +498,7 @@ where /// Shifts the mask elements to the left by `OFFSET`, filling in with /// `padding` from the right. #[inline] - #[must_use = "method returns a new vector and does not mutate the original inputs"] + #[must_use = "method returns a new mask and does not mutate the original inputs"] pub fn shift_elements_left(self, padding: T) -> Self { // Safety: swizzles are safe for masks unsafe { Self::from_int_unchecked(self.to_int().shift_elements_left::(padding)) } From c9c0bf97f031cc7ab15209cd12b18ab72d019941 Mon Sep 17 00:00:00 2001 From: Sam Shepard Date: Fri, 27 Sep 2024 21:05:07 -0400 Subject: [PATCH 5/6] Update crates/core_simd/src/swizzle.rs Co-authored-by: Caleb Zulawski --- 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 a7833ea92c0..3b552016cb5 100644 --- a/crates/core_simd/src/swizzle.rs +++ b/crates/core_simd/src/swizzle.rs @@ -507,7 +507,7 @@ where /// Shifts the mask elements to the right by `OFFSET`, filling in with /// `padding` from the left. #[inline] - #[must_use = "method returns a new vector and does not mutate the original inputs"] + #[must_use = "method returns a new mask and does not mutate the original inputs"] pub fn shift_elements_right(self, padding: T) -> Self { // Safety: swizzles are safe for masks unsafe { Self::from_int_unchecked(self.to_int().shift_elements_right::(padding)) } From 9392fb1c2b73b453a53392ebfd52462100e0c430 Mon Sep 17 00:00:00 2001 From: Samuel Shepard Date: Fri, 27 Sep 2024 21:27:47 -0400 Subject: [PATCH 6/6] Change mask function to accept bool --- crates/core_simd/src/swizzle.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/crates/core_simd/src/swizzle.rs b/crates/core_simd/src/swizzle.rs index 3b552016cb5..dbd84543064 100644 --- a/crates/core_simd/src/swizzle.rs +++ b/crates/core_simd/src/swizzle.rs @@ -499,18 +499,30 @@ where /// `padding` from the right. #[inline] #[must_use = "method returns a new mask and does not mutate the original inputs"] - pub fn shift_elements_left(self, padding: T) -> Self { + pub fn shift_elements_left(self, padding: bool) -> Self { // Safety: swizzles are safe for masks - unsafe { Self::from_int_unchecked(self.to_int().shift_elements_left::(padding)) } + unsafe { + Self::from_int_unchecked(self.to_int().shift_elements_left::(if padding { + T::TRUE + } else { + T::FALSE + })) + } } /// Shifts the mask elements to the right by `OFFSET`, filling in with /// `padding` from the left. #[inline] #[must_use = "method returns a new mask and does not mutate the original inputs"] - pub fn shift_elements_right(self, padding: T) -> Self { + pub fn shift_elements_right(self, padding: bool) -> Self { // Safety: swizzles are safe for masks - unsafe { Self::from_int_unchecked(self.to_int().shift_elements_right::(padding)) } + unsafe { + Self::from_int_unchecked(self.to_int().shift_elements_right::(if padding { + T::TRUE + } else { + T::FALSE + })) + } } /// Interleave two masks.