Skip to content

Commit d3cfd7c

Browse files
committed
Add vectors of pointers
1 parent 7c80b69 commit d3cfd7c

File tree

8 files changed

+339
-3
lines changed

8 files changed

+339
-3
lines changed

crates/core_simd/src/cast.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use crate::simd::SimdElement;
2+
3+
/// Supporting trait for `Simd::cast`. Typically doesn't need to be used directly.
4+
pub trait SimdCast<Target: SimdElement>: SimdElement {}
5+
6+
macro_rules! into_number {
7+
{ $($type:ty),* } => {
8+
$(
9+
impl SimdCast<i8> for $type {}
10+
impl SimdCast<i16> for $type {}
11+
impl SimdCast<i32> for $type {}
12+
impl SimdCast<i64> for $type {}
13+
impl SimdCast<isize> for $type {}
14+
15+
impl SimdCast<u8> for $type {}
16+
impl SimdCast<u16> for $type {}
17+
impl SimdCast<u32> for $type {}
18+
impl SimdCast<u64> for $type {}
19+
impl SimdCast<usize> for $type {}
20+
21+
impl SimdCast<f32> for $type {}
22+
impl SimdCast<f64> for $type {}
23+
)*
24+
}
25+
}
26+
27+
into_number! { i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64 }
28+
29+
macro_rules! into_pointer {
30+
{ $($type:ty),* } => {
31+
$(
32+
impl<T> SimdCast<$type> for *const T {}
33+
impl<T> SimdCast<$type> for *mut T {}
34+
impl<T> SimdCast<*const T> for $type {}
35+
impl<T> SimdCast<*mut T> for $type {}
36+
)*
37+
}
38+
}
39+
40+
into_pointer! { i8, i16, i32, i64, isize, u8, u16, u32, u64, usize }
41+
42+
impl<T, U> SimdCast<*const T> for *const U {}
43+
impl<T, U> SimdCast<*const T> for *mut U {}
44+
impl<T, U> SimdCast<*mut T> for *const U {}
45+
impl<T, U> SimdCast<*mut T> for *mut U {}

crates/core_simd/src/elements.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1+
mod const_ptr;
12
mod float;
23
mod int;
4+
mod mut_ptr;
35
mod uint;
46

57
mod sealed {
68
pub trait Sealed {}
79
}
810

11+
pub use const_ptr::*;
912
pub use float::*;
1013
pub use int::*;
14+
pub use mut_ptr::*;
1115
pub use uint::*;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use super::sealed::Sealed;
2+
use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount};
3+
4+
/// Operations on SIMD vectors of constant pointers.
5+
pub trait SimdConstPtr: Copy + Sealed {
6+
/// Vector type representing the pointers as bits.
7+
type Bits;
8+
9+
/// Vector of mutable pointers to the same type.
10+
type MutPtr;
11+
12+
/// Mask type used for manipulating this SIMD vector type.
13+
type Mask;
14+
15+
/// Returns `true` for each lane that is null.
16+
fn is_null(self) -> Self::Mask;
17+
18+
/// Changes constness without changing the type.
19+
fn as_mut(self) -> Self::MutPtr;
20+
21+
/// Cast pointers to raw bits.
22+
fn to_bits(self) -> Self::Bits;
23+
24+
/// Cast raw bits to pointers.
25+
fn from_bits(bits: Self::Bits) -> Self;
26+
}
27+
28+
impl<T, const LANES: usize> Sealed for Simd<*const T, LANES> where
29+
LaneCount<LANES>: SupportedLaneCount
30+
{
31+
}
32+
33+
impl<T, const LANES: usize> SimdConstPtr for Simd<*const T, LANES>
34+
where
35+
LaneCount<LANES>: SupportedLaneCount,
36+
{
37+
type Bits = Simd<usize, LANES>;
38+
type MutPtr = Simd<*mut T, LANES>;
39+
type Mask = Mask<isize, LANES>;
40+
41+
fn is_null(self) -> Self::Mask {
42+
Simd::splat(core::ptr::null()).simd_eq(self)
43+
}
44+
45+
fn as_mut(self) -> Self::MutPtr {
46+
// Converting between pointers is safe
47+
unsafe { intrinsics::simd_as(self) }
48+
}
49+
50+
fn to_bits(self) -> Self::Bits {
51+
// Casting pointers to usize is safe
52+
unsafe { intrinsics::simd_as(self) }
53+
}
54+
55+
fn from_bits(bits: Self::Bits) -> Self {
56+
// Casting usize to pointers is safe
57+
unsafe { intrinsics::simd_as(bits) }
58+
}
59+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use super::sealed::Sealed;
2+
use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount};
3+
4+
/// Operations on SIMD vectors of mutable pointers.
5+
pub trait SimdMutPtr: Copy + Sealed {
6+
/// Vector type representing the pointers as bits.
7+
type Bits;
8+
9+
/// Vector of constant pointers to the same type.
10+
type ConstPtr;
11+
12+
/// Mask type used for manipulating this SIMD vector type.
13+
type Mask;
14+
15+
/// Returns `true` for each lane that is null.
16+
fn is_null(self) -> Self::Mask;
17+
18+
/// Changes constness without changing the type.
19+
fn as_const(self) -> Self::ConstPtr;
20+
21+
/// Cast pointers to raw bits.
22+
fn to_bits(self) -> Self::Bits;
23+
24+
/// Cast raw bits to pointers.
25+
fn from_bits(bits: Self::Bits) -> Self;
26+
}
27+
28+
impl<T, const LANES: usize> Sealed for Simd<*mut T, LANES> where LaneCount<LANES>: SupportedLaneCount
29+
{}
30+
31+
impl<T, const LANES: usize> SimdMutPtr for Simd<*mut T, LANES>
32+
where
33+
LaneCount<LANES>: SupportedLaneCount,
34+
{
35+
type Bits = Simd<usize, LANES>;
36+
type ConstPtr = Simd<*const T, LANES>;
37+
type Mask = Mask<isize, LANES>;
38+
39+
fn is_null(self) -> Self::Mask {
40+
Simd::splat(core::ptr::null_mut()).simd_eq(self)
41+
}
42+
43+
fn as_const(self) -> Self::ConstPtr {
44+
// Converting between pointers is safe
45+
unsafe { intrinsics::simd_as(self) }
46+
}
47+
48+
fn to_bits(self) -> Self::Bits {
49+
// Casting pointers to usize is safe
50+
unsafe { intrinsics::simd_as(self) }
51+
}
52+
53+
fn from_bits(bits: Self::Bits) -> Self {
54+
// Casting usize to pointers is safe
55+
unsafe { intrinsics::simd_as(bits) }
56+
}
57+
}

crates/core_simd/src/eq.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,45 @@ macro_rules! impl_mask {
7171
}
7272

7373
impl_mask! { i8, i16, i32, i64, isize }
74+
75+
impl<T, const LANES: usize> SimdPartialEq for Simd<*const T, LANES>
76+
where
77+
LaneCount<LANES>: SupportedLaneCount,
78+
{
79+
type Mask = Mask<isize, LANES>;
80+
81+
#[inline]
82+
fn simd_eq(self, other: Self) -> Self::Mask {
83+
// Safety: `self` is a vector, and the result of the comparison
84+
// is always a valid mask.
85+
unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) }
86+
}
87+
88+
#[inline]
89+
fn simd_ne(self, other: Self) -> Self::Mask {
90+
// Safety: `self` is a vector, and the result of the comparison
91+
// is always a valid mask.
92+
unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) }
93+
}
94+
}
95+
96+
impl<T, const LANES: usize> SimdPartialEq for Simd<*mut T, LANES>
97+
where
98+
LaneCount<LANES>: SupportedLaneCount,
99+
{
100+
type Mask = Mask<isize, LANES>;
101+
102+
#[inline]
103+
fn simd_eq(self, other: Self) -> Self::Mask {
104+
// Safety: `self` is a vector, and the result of the comparison
105+
// is always a valid mask.
106+
unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) }
107+
}
108+
109+
#[inline]
110+
fn simd_ne(self, other: Self) -> Self::Mask {
111+
// Safety: `self` is a vector, and the result of the comparison
112+
// is always a valid mask.
113+
unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) }
114+
}
115+
}

crates/core_simd/src/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub(crate) mod intrinsics;
77
mod to_bytes;
88

99
mod alias;
10+
mod cast;
1011
mod elements;
1112
mod eq;
1213
mod fmt;
@@ -24,6 +25,7 @@ pub mod simd {
2425
pub(crate) use crate::core_simd::intrinsics;
2526

2627
pub use crate::core_simd::alias::*;
28+
pub use crate::core_simd::cast::*;
2729
pub use crate::core_simd::elements::*;
2830
pub use crate::core_simd::eq::*;
2931
pub use crate::core_simd::lane_count::{LaneCount, SupportedLaneCount};

crates/core_simd/src/ord.rs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,3 +211,117 @@ macro_rules! impl_mask {
211211
}
212212

213213
impl_mask! { i8, i16, i32, i64, isize }
214+
215+
impl<T, const LANES: usize> SimdPartialOrd for Simd<*const T, LANES>
216+
where
217+
LaneCount<LANES>: SupportedLaneCount,
218+
{
219+
#[inline]
220+
fn simd_lt(self, other: Self) -> Self::Mask {
221+
// Safety: `self` is a vector, and the result of the comparison
222+
// is always a valid mask.
223+
unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
224+
}
225+
226+
#[inline]
227+
fn simd_le(self, other: Self) -> Self::Mask {
228+
// Safety: `self` is a vector, and the result of the comparison
229+
// is always a valid mask.
230+
unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
231+
}
232+
233+
#[inline]
234+
fn simd_gt(self, other: Self) -> Self::Mask {
235+
// Safety: `self` is a vector, and the result of the comparison
236+
// is always a valid mask.
237+
unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
238+
}
239+
240+
#[inline]
241+
fn simd_ge(self, other: Self) -> Self::Mask {
242+
// Safety: `self` is a vector, and the result of the comparison
243+
// is always a valid mask.
244+
unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
245+
}
246+
}
247+
248+
impl<T, const LANES: usize> SimdOrd for Simd<*const T, LANES>
249+
where
250+
LaneCount<LANES>: SupportedLaneCount,
251+
{
252+
#[inline]
253+
fn simd_max(self, other: Self) -> Self {
254+
self.simd_lt(other).select(other, self)
255+
}
256+
257+
#[inline]
258+
fn simd_min(self, other: Self) -> Self {
259+
self.simd_gt(other).select(other, self)
260+
}
261+
262+
#[inline]
263+
fn simd_clamp(self, min: Self, max: Self) -> Self {
264+
assert!(
265+
min.simd_le(max).all(),
266+
"each lane in `min` must be less than or equal to the corresponding lane in `max`",
267+
);
268+
self.simd_max(min).simd_min(max)
269+
}
270+
}
271+
272+
impl<T, const LANES: usize> SimdPartialOrd for Simd<*mut T, LANES>
273+
where
274+
LaneCount<LANES>: SupportedLaneCount,
275+
{
276+
#[inline]
277+
fn simd_lt(self, other: Self) -> Self::Mask {
278+
// Safety: `self` is a vector, and the result of the comparison
279+
// is always a valid mask.
280+
unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
281+
}
282+
283+
#[inline]
284+
fn simd_le(self, other: Self) -> Self::Mask {
285+
// Safety: `self` is a vector, and the result of the comparison
286+
// is always a valid mask.
287+
unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
288+
}
289+
290+
#[inline]
291+
fn simd_gt(self, other: Self) -> Self::Mask {
292+
// Safety: `self` is a vector, and the result of the comparison
293+
// is always a valid mask.
294+
unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
295+
}
296+
297+
#[inline]
298+
fn simd_ge(self, other: Self) -> Self::Mask {
299+
// Safety: `self` is a vector, and the result of the comparison
300+
// is always a valid mask.
301+
unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
302+
}
303+
}
304+
305+
impl<T, const LANES: usize> SimdOrd for Simd<*mut T, LANES>
306+
where
307+
LaneCount<LANES>: SupportedLaneCount,
308+
{
309+
#[inline]
310+
fn simd_max(self, other: Self) -> Self {
311+
self.simd_lt(other).select(other, self)
312+
}
313+
314+
#[inline]
315+
fn simd_min(self, other: Self) -> Self {
316+
self.simd_gt(other).select(other, self)
317+
}
318+
319+
#[inline]
320+
fn simd_clamp(self, min: Self, max: Self) -> Self {
321+
assert!(
322+
min.simd_le(max).all(),
323+
"each lane in `min` must be less than or equal to the corresponding lane in `max`",
324+
);
325+
self.simd_max(min).simd_min(max)
326+
}
327+
}

0 commit comments

Comments
 (0)