From f10e591de1d321b57af68502a78eef6f8f80c05c Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Fri, 24 Jun 2022 00:13:36 -0400 Subject: [PATCH] Fix wrapping pointer arithmetic --- crates/core_simd/src/elements/const_ptr.rs | 33 ++++++++++++++++++---- crates/core_simd/src/elements/mut_ptr.rs | 33 ++++++++++++++++++---- crates/core_simd/src/intrinsics.rs | 3 ++ crates/core_simd/tests/pointers.rs | 16 +++++++++++ 4 files changed, 75 insertions(+), 10 deletions(-) diff --git a/crates/core_simd/src/elements/const_ptr.rs b/crates/core_simd/src/elements/const_ptr.rs index c4a254f5ab1..d10bd1481d0 100644 --- a/crates/core_simd/src/elements/const_ptr.rs +++ b/crates/core_simd/src/elements/const_ptr.rs @@ -1,11 +1,14 @@ use super::sealed::Sealed; -use crate::simd::{LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount}; +use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount}; /// Operations on SIMD vectors of constant pointers. pub trait SimdConstPtr: Copy + Sealed { - /// Vector of usize with the same number of lanes. + /// Vector of `usize` with the same number of lanes. type Usize; + /// Vector of `isize` with the same number of lanes. + type Isize; + /// Vector of mutable pointers to the same type. type MutPtr; @@ -23,10 +26,20 @@ pub trait SimdConstPtr: Copy + Sealed { /// Equivalent to calling [`pointer::addr`] on each lane. fn addr(self) -> Self::Usize; + /// Calculates the offset from a pointer using wrapping arithmetic. + /// + /// Equivalent to calling [`pointer::wrapping_offset`] on each lane. + fn wrapping_offset(self, offset: Self::Isize) -> Self; + /// Calculates the offset from a pointer using wrapping arithmetic. /// /// Equivalent to calling [`pointer::wrapping_add`] on each lane. fn wrapping_add(self, count: Self::Usize) -> Self; + + /// Calculates the offset from a pointer using wrapping arithmetic. + /// + /// Equivalent to calling [`pointer::wrapping_add`] on each lane. + fn wrapping_sub(self, count: Self::Usize) -> Self; } impl Sealed for Simd<*const T, LANES> where @@ -39,6 +52,7 @@ impl SimdConstPtr for Simd<*const T, LANES> LaneCount: SupportedLaneCount, { type Usize = Simd; + type Isize = Simd; type MutPtr = Simd<*mut T, LANES>; type Mask = Mask; @@ -57,10 +71,19 @@ fn addr(self) -> Self::Usize { self.cast() } + #[inline] + fn wrapping_offset(self, count: Self::Isize) -> Self { + // Safety: simd_arith_offset takes a vector of pointers and a vector of offsets + unsafe { intrinsics::simd_arith_offset(self, count) } + } + #[inline] fn wrapping_add(self, count: Self::Usize) -> Self { - let addr = self.addr() + (count * Simd::splat(core::mem::size_of::())); - // Safety: transmuting usize to pointers is safe, even if accessing those pointers isn't. - unsafe { core::mem::transmute_copy(&addr) } + self.wrapping_offset(count.cast()) + } + + #[inline] + fn wrapping_sub(self, count: Self::Usize) -> Self { + self.wrapping_offset(-count.cast::()) } } diff --git a/crates/core_simd/src/elements/mut_ptr.rs b/crates/core_simd/src/elements/mut_ptr.rs index 5920960c49c..4fc6202e14e 100644 --- a/crates/core_simd/src/elements/mut_ptr.rs +++ b/crates/core_simd/src/elements/mut_ptr.rs @@ -1,11 +1,14 @@ use super::sealed::Sealed; -use crate::simd::{LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount}; +use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount}; /// Operations on SIMD vectors of mutable pointers. pub trait SimdMutPtr: Copy + Sealed { - /// Vector of usize with the same number of lanes. + /// Vector of `usize` with the same number of lanes. type Usize; + /// Vector of `isize` with the same number of lanes. + type Isize; + /// Vector of constant pointers to the same type. type ConstPtr; @@ -23,10 +26,20 @@ pub trait SimdMutPtr: Copy + Sealed { /// Equivalent to calling [`pointer::addr`] on each lane. fn addr(self) -> Self::Usize; + /// Calculates the offset from a pointer using wrapping arithmetic. + /// + /// Equivalent to calling [`pointer::wrapping_offset`] on each lane. + fn wrapping_offset(self, offset: Self::Isize) -> Self; + /// Calculates the offset from a pointer using wrapping arithmetic. /// /// Equivalent to calling [`pointer::wrapping_add`] on each lane. fn wrapping_add(self, count: Self::Usize) -> Self; + + /// Calculates the offset from a pointer using wrapping arithmetic. + /// + /// Equivalent to calling [`pointer::wrapping_add`] on each lane. + fn wrapping_sub(self, count: Self::Usize) -> Self; } impl Sealed for Simd<*mut T, LANES> where LaneCount: SupportedLaneCount @@ -37,6 +50,7 @@ impl SimdMutPtr for Simd<*mut T, LANES> LaneCount: SupportedLaneCount, { type Usize = Simd; + type Isize = Simd; type ConstPtr = Simd<*const T, LANES>; type Mask = Mask; @@ -55,10 +69,19 @@ fn addr(self) -> Self::Usize { self.cast() } + #[inline] + fn wrapping_offset(self, count: Self::Isize) -> Self { + // Safety: simd_arith_offset takes a vector of pointers and a vector of offsets + unsafe { intrinsics::simd_arith_offset(self, count) } + } + #[inline] fn wrapping_add(self, count: Self::Usize) -> Self { - let addr = self.addr() + (count * Simd::splat(core::mem::size_of::())); - // Safety: transmuting usize to pointers is safe, even if accessing those pointers isn't. - unsafe { core::mem::transmute_copy(&addr) } + self.wrapping_offset(count.cast()) + } + + #[inline] + fn wrapping_sub(self, count: Self::Usize) -> Self { + self.wrapping_offset(-count.cast::()) } } diff --git a/crates/core_simd/src/intrinsics.rs b/crates/core_simd/src/intrinsics.rs index 6047890a093..41128cd1481 100644 --- a/crates/core_simd/src/intrinsics.rs +++ b/crates/core_simd/src/intrinsics.rs @@ -151,4 +151,7 @@ pub(crate) fn simd_select(m: M, yes: T, no: T) -> T; #[allow(unused)] pub(crate) fn simd_select_bitmask(m: M, yes: T, no: T) -> T; + + // equivalent to wrapping_offset + pub(crate) fn simd_arith_offset(ptr: T, offset: U) -> T; } diff --git a/crates/core_simd/tests/pointers.rs b/crates/core_simd/tests/pointers.rs index df26c462f93..2c20362119e 100644 --- a/crates/core_simd/tests/pointers.rs +++ b/crates/core_simd/tests/pointers.rs @@ -21,6 +21,14 @@ fn addr() { ); } + fn wrapping_offset() { + test_helpers::test_binary_elementwise( + &Simd::<*$constness (), LANES>::wrapping_offset, + &<*$constness ()>::wrapping_offset, + &|_, _| true, + ); + } + fn wrapping_add() { test_helpers::test_binary_elementwise( &Simd::<*$constness (), LANES>::wrapping_add, @@ -28,6 +36,14 @@ fn wrapping_add() { &|_, _| true, ); } + + fn wrapping_sub() { + test_helpers::test_binary_elementwise( + &Simd::<*$constness (), LANES>::wrapping_sub, + &<*$constness ()>::wrapping_sub, + &|_, _| true, + ); + } } } }