Skip to content

Commit f10e591

Browse files
committed
Fix wrapping pointer arithmetic
1 parent 6b3c599 commit f10e591

File tree

4 files changed

+75
-10
lines changed

4 files changed

+75
-10
lines changed

crates/core_simd/src/elements/const_ptr.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
use super::sealed::Sealed;
2-
use crate::simd::{LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount};
2+
use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount};
33

44
/// Operations on SIMD vectors of constant pointers.
55
pub trait SimdConstPtr: Copy + Sealed {
6-
/// Vector of usize with the same number of lanes.
6+
/// Vector of `usize` with the same number of lanes.
77
type Usize;
88

9+
/// Vector of `isize` with the same number of lanes.
10+
type Isize;
11+
912
/// Vector of mutable pointers to the same type.
1013
type MutPtr;
1114

@@ -23,10 +26,20 @@ pub trait SimdConstPtr: Copy + Sealed {
2326
/// Equivalent to calling [`pointer::addr`] on each lane.
2427
fn addr(self) -> Self::Usize;
2528

29+
/// Calculates the offset from a pointer using wrapping arithmetic.
30+
///
31+
/// Equivalent to calling [`pointer::wrapping_offset`] on each lane.
32+
fn wrapping_offset(self, offset: Self::Isize) -> Self;
33+
2634
/// Calculates the offset from a pointer using wrapping arithmetic.
2735
///
2836
/// Equivalent to calling [`pointer::wrapping_add`] on each lane.
2937
fn wrapping_add(self, count: Self::Usize) -> Self;
38+
39+
/// Calculates the offset from a pointer using wrapping arithmetic.
40+
///
41+
/// Equivalent to calling [`pointer::wrapping_add`] on each lane.
42+
fn wrapping_sub(self, count: Self::Usize) -> Self;
3043
}
3144

3245
impl<T, const LANES: usize> Sealed for Simd<*const T, LANES> where
@@ -39,6 +52,7 @@ where
3952
LaneCount<LANES>: SupportedLaneCount,
4053
{
4154
type Usize = Simd<usize, LANES>;
55+
type Isize = Simd<isize, LANES>;
4256
type MutPtr = Simd<*mut T, LANES>;
4357
type Mask = Mask<isize, LANES>;
4458

@@ -57,10 +71,19 @@ where
5771
self.cast()
5872
}
5973

74+
#[inline]
75+
fn wrapping_offset(self, count: Self::Isize) -> Self {
76+
// Safety: simd_arith_offset takes a vector of pointers and a vector of offsets
77+
unsafe { intrinsics::simd_arith_offset(self, count) }
78+
}
79+
6080
#[inline]
6181
fn wrapping_add(self, count: Self::Usize) -> Self {
62-
let addr = self.addr() + (count * Simd::splat(core::mem::size_of::<T>()));
63-
// Safety: transmuting usize to pointers is safe, even if accessing those pointers isn't.
64-
unsafe { core::mem::transmute_copy(&addr) }
82+
self.wrapping_offset(count.cast())
83+
}
84+
85+
#[inline]
86+
fn wrapping_sub(self, count: Self::Usize) -> Self {
87+
self.wrapping_offset(-count.cast::<isize>())
6588
}
6689
}

crates/core_simd/src/elements/mut_ptr.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
use super::sealed::Sealed;
2-
use crate::simd::{LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount};
2+
use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount};
33

44
/// Operations on SIMD vectors of mutable pointers.
55
pub trait SimdMutPtr: Copy + Sealed {
6-
/// Vector of usize with the same number of lanes.
6+
/// Vector of `usize` with the same number of lanes.
77
type Usize;
88

9+
/// Vector of `isize` with the same number of lanes.
10+
type Isize;
11+
912
/// Vector of constant pointers to the same type.
1013
type ConstPtr;
1114

@@ -23,10 +26,20 @@ pub trait SimdMutPtr: Copy + Sealed {
2326
/// Equivalent to calling [`pointer::addr`] on each lane.
2427
fn addr(self) -> Self::Usize;
2528

29+
/// Calculates the offset from a pointer using wrapping arithmetic.
30+
///
31+
/// Equivalent to calling [`pointer::wrapping_offset`] on each lane.
32+
fn wrapping_offset(self, offset: Self::Isize) -> Self;
33+
2634
/// Calculates the offset from a pointer using wrapping arithmetic.
2735
///
2836
/// Equivalent to calling [`pointer::wrapping_add`] on each lane.
2937
fn wrapping_add(self, count: Self::Usize) -> Self;
38+
39+
/// Calculates the offset from a pointer using wrapping arithmetic.
40+
///
41+
/// Equivalent to calling [`pointer::wrapping_add`] on each lane.
42+
fn wrapping_sub(self, count: Self::Usize) -> Self;
3043
}
3144

3245
impl<T, const LANES: usize> Sealed for Simd<*mut T, LANES> where LaneCount<LANES>: SupportedLaneCount
@@ -37,6 +50,7 @@ where
3750
LaneCount<LANES>: SupportedLaneCount,
3851
{
3952
type Usize = Simd<usize, LANES>;
53+
type Isize = Simd<isize, LANES>;
4054
type ConstPtr = Simd<*const T, LANES>;
4155
type Mask = Mask<isize, LANES>;
4256

@@ -55,10 +69,19 @@ where
5569
self.cast()
5670
}
5771

72+
#[inline]
73+
fn wrapping_offset(self, count: Self::Isize) -> Self {
74+
// Safety: simd_arith_offset takes a vector of pointers and a vector of offsets
75+
unsafe { intrinsics::simd_arith_offset(self, count) }
76+
}
77+
5878
#[inline]
5979
fn wrapping_add(self, count: Self::Usize) -> Self {
60-
let addr = self.addr() + (count * Simd::splat(core::mem::size_of::<T>()));
61-
// Safety: transmuting usize to pointers is safe, even if accessing those pointers isn't.
62-
unsafe { core::mem::transmute_copy(&addr) }
80+
self.wrapping_offset(count.cast())
81+
}
82+
83+
#[inline]
84+
fn wrapping_sub(self, count: Self::Usize) -> Self {
85+
self.wrapping_offset(-count.cast::<isize>())
6386
}
6487
}

crates/core_simd/src/intrinsics.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,7 @@ extern "platform-intrinsic" {
151151
pub(crate) fn simd_select<M, T>(m: M, yes: T, no: T) -> T;
152152
#[allow(unused)]
153153
pub(crate) fn simd_select_bitmask<M, T>(m: M, yes: T, no: T) -> T;
154+
155+
// equivalent to wrapping_offset
156+
pub(crate) fn simd_arith_offset<T, U>(ptr: T, offset: U) -> T;
154157
}

crates/core_simd/tests/pointers.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,29 @@ macro_rules! common_tests {
2121
);
2222
}
2323

24+
fn wrapping_offset<const LANES: usize>() {
25+
test_helpers::test_binary_elementwise(
26+
&Simd::<*$constness (), LANES>::wrapping_offset,
27+
&<*$constness ()>::wrapping_offset,
28+
&|_, _| true,
29+
);
30+
}
31+
2432
fn wrapping_add<const LANES: usize>() {
2533
test_helpers::test_binary_elementwise(
2634
&Simd::<*$constness (), LANES>::wrapping_add,
2735
&<*$constness ()>::wrapping_add,
2836
&|_, _| true,
2937
);
3038
}
39+
40+
fn wrapping_sub<const LANES: usize>() {
41+
test_helpers::test_binary_elementwise(
42+
&Simd::<*$constness (), LANES>::wrapping_sub,
43+
&<*$constness ()>::wrapping_sub,
44+
&|_, _| true,
45+
);
46+
}
3147
}
3248
}
3349
}

0 commit comments

Comments
 (0)