Skip to content

Commit e7cc021

Browse files
committed
Fix casts
1 parent da25087 commit e7cc021

File tree

4 files changed

+115
-111
lines changed

4 files changed

+115
-111
lines changed

crates/core_simd/src/cast.rs

Lines changed: 54 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,79 @@
11
use crate::simd::{intrinsics, LaneCount, Simd, SimdElement, SupportedLaneCount};
22

33
/// Supporting trait for `Simd::cast`. Typically doesn't need to be used directly.
4-
pub trait SimdCast<Target: SimdElement>: SimdElement {
4+
pub unsafe trait SimdCast<Target: SimdElement>: SimdElement {
55
#[doc(hidden)]
66
fn cast<const LANES: usize>(x: Simd<Self, LANES>) -> Simd<Target, LANES>
77
where
8-
LaneCount<LANES>: SupportedLaneCount;
8+
LaneCount<LANES>: SupportedLaneCount,
9+
{
10+
// Safety: implementing this trait indicates that the types are supported by `simd_as`
11+
unsafe { intrinsics::simd_as(x) }
12+
}
13+
14+
#[doc(hidden)]
15+
unsafe fn cast_unchecked<const LANES: usize>(x: Simd<Self, LANES>) -> Simd<Target, LANES>
16+
where
17+
LaneCount<LANES>: SupportedLaneCount,
18+
{
19+
// Safety: implementing this trait indicates that the types are supported by `simd_cast`
20+
// The caller is responsible for the conversion invariants.
21+
unsafe { intrinsics::simd_cast(x) }
22+
}
923
}
1024

1125
macro_rules! into_number {
12-
{ $from:ty, $to:ty } => {
13-
impl SimdCast<$to> for $from {
14-
fn cast<const LANES: usize>(x: Simd<Self, LANES>) -> Simd<$to, LANES>
15-
where
16-
LaneCount<LANES>: SupportedLaneCount,
17-
{
18-
// Safety: simd_as can handle numeric conversions
19-
unsafe { intrinsics::simd_as(x) }
20-
}
21-
}
26+
{ unsafe $from:ty as $to:ty } => {
27+
// Safety: casting between numbers is supported by `simd_cast` and `simd_as`
28+
unsafe impl SimdCast<$to> for $from {}
2229
};
23-
{ $($type:ty),* } => {
30+
{ unsafe $($type:ty),* } => {
2431
$(
25-
into_number! { $type, i8 }
26-
into_number! { $type, i16 }
27-
into_number! { $type, i32 }
28-
into_number! { $type, i64 }
29-
into_number! { $type, isize }
32+
into_number! { unsafe $type as i8 }
33+
into_number! { unsafe $type as i16 }
34+
into_number! { unsafe $type as i32 }
35+
into_number! { unsafe $type as i64 }
36+
into_number! { unsafe $type as isize }
3037

31-
into_number! { $type, u8 }
32-
into_number! { $type, u16 }
33-
into_number! { $type, u32 }
34-
into_number! { $type, u64 }
35-
into_number! { $type, usize }
38+
into_number! { unsafe $type as u8 }
39+
into_number! { unsafe $type as u16 }
40+
into_number! { unsafe $type as u32 }
41+
into_number! { unsafe $type as u64 }
42+
into_number! { unsafe $type as usize }
3643

37-
into_number! { $type, f32 }
38-
into_number! { $type, f64 }
44+
into_number! { unsafe $type as f32 }
45+
into_number! { unsafe $type as f64 }
3946
)*
4047
}
4148
}
4249

43-
into_number! { i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64 }
50+
into_number! { unsafe i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64 }
4451

52+
// TODO uncomment pending PR to rustc
53+
/*
4554
macro_rules! into_pointer {
46-
{ $($type:ty),* } => {
55+
{ unsafe $($type:ty),* } => {
4756
$(
48-
impl<T> SimdCast<$type> for *const T {
49-
fn cast<const LANES: usize>(x: Simd<Self, LANES>) -> Simd<$type, LANES>
50-
where
51-
LaneCount<LANES>: SupportedLaneCount,
52-
{
53-
// Safety: transmuting isize to pointers is safe
54-
let x: Simd<isize, LANES> = unsafe { core::mem::transmute_copy(&x) };
55-
x.cast()
56-
}
57-
}
58-
impl<T> SimdCast<$type> for *mut T {
59-
fn cast<const LANES: usize>(x: Simd<Self, LANES>) -> Simd<$type, LANES>
60-
where
61-
LaneCount<LANES>: SupportedLaneCount,
62-
{
63-
// Safety: transmuting isize to pointers is safe
64-
let x: Simd<isize, LANES> = unsafe { core::mem::transmute_copy(&x) };
65-
x.cast()
66-
}
67-
}
68-
impl<T> SimdCast<*const T> for $type {
69-
fn cast<const LANES: usize>(x: Simd<$type, LANES>) -> Simd<*const T, LANES>
70-
where
71-
LaneCount<LANES>: SupportedLaneCount,
72-
{
73-
let x: Simd<isize, LANES> = x.cast();
74-
// Safety: transmuting isize to pointers is safe
75-
unsafe { core::mem::transmute_copy(&x) }
76-
}
77-
}
78-
impl<T> SimdCast<*mut T> for $type {
79-
fn cast<const LANES: usize>(x: Simd<$type, LANES>) -> Simd<*mut T, LANES>
80-
where
81-
LaneCount<LANES>: SupportedLaneCount,
82-
{
83-
let x: Simd<isize, LANES> = x.cast();
84-
// Safety: transmuting isize to pointers is safe
85-
unsafe { core::mem::transmute_copy(&x) }
86-
}
87-
}
57+
// Safety: casting between numbers and pointers is supported by `simd_cast` and `simd_as`
58+
unsafe impl<T> SimdCast<$type> for *const T {}
59+
// Safety: casting between numbers and pointers is supported by `simd_cast` and `simd_as`
60+
unsafe impl<T> SimdCast<$type> for *mut T {}
61+
// Safety: casting between numbers and pointers is supported by `simd_cast` and `simd_as`
62+
unsafe impl<T> SimdCast<*const T> for $type {}
63+
// Safety: casting between numbers and pointers is supported by `simd_cast` and `simd_as`
64+
unsafe impl<T> SimdCast<*mut T> for $type {}
8865
)*
8966
}
9067
}
9168
92-
into_pointer! { i8, i16, i32, i64, isize, u8, u16, u32, u64, usize }
69+
into_pointer! { unsafe i8, i16, i32, i64, isize, u8, u16, u32, u64, usize }
9370
94-
impl<T, U> SimdCast<*const T> for *const U {
95-
fn cast<const LANES: usize>(x: Simd<*const U, LANES>) -> Simd<*const T, LANES>
96-
where
97-
LaneCount<LANES>: SupportedLaneCount,
98-
{
99-
// Safety: transmuting pointers is safe
100-
unsafe { core::mem::transmute_copy(&x) }
101-
}
102-
}
103-
impl<T, U> SimdCast<*const T> for *mut U {
104-
fn cast<const LANES: usize>(x: Simd<*mut U, LANES>) -> Simd<*const T, LANES>
105-
where
106-
LaneCount<LANES>: SupportedLaneCount,
107-
{
108-
// Safety: transmuting pointers is safe
109-
unsafe { core::mem::transmute_copy(&x) }
110-
}
111-
}
112-
impl<T, U> SimdCast<*mut T> for *const U {
113-
fn cast<const LANES: usize>(x: Simd<*const U, LANES>) -> Simd<*mut T, LANES>
114-
where
115-
LaneCount<LANES>: SupportedLaneCount,
116-
{
117-
// Safety: transmuting pointers is safe
118-
unsafe { core::mem::transmute_copy(&x) }
119-
}
120-
}
121-
impl<T, U> SimdCast<*mut T> for *mut U {
122-
fn cast<const LANES: usize>(x: Simd<*mut U, LANES>) -> Simd<*mut T, LANES>
123-
where
124-
LaneCount<LANES>: SupportedLaneCount,
125-
{
126-
// Safety: transmuting pointers is safe
127-
unsafe { core::mem::transmute_copy(&x) }
128-
}
129-
}
71+
// Safety: casting between pointers is supported by `simd_cast` and `simd_as`
72+
unsafe impl<T, U> SimdCast<*const T> for *const U {}
73+
// Safety: casting between pointers is supported by `simd_cast` and `simd_as`
74+
unsafe impl<T, U> SimdCast<*const T> for *mut U {}
75+
// Safety: casting between pointers is supported by `simd_cast` and `simd_as`
76+
unsafe impl<T, U> SimdCast<*mut T> for *const U {}
77+
// Safety: casting between pointers is supported by `simd_cast` and `simd_as`
78+
unsafe impl<T, U> SimdCast<*mut T> for *mut U {}
79+
*/

crates/core_simd/src/elements/const_ptr.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,23 @@ pub trait SimdConstPtr: Copy + Sealed {
2323

2424
/// Gets the "address" portion of the pointer.
2525
///
26+
/// This method discards pointer semantic metadata, so the result cannot be
27+
/// directly cast into a valid pointer.
28+
///
29+
/// This method semantically discards *provenance* and
30+
/// *address-space* information. To properly restore that information, use [`with_addr`].
31+
///
2632
/// Equivalent to calling [`pointer::addr`] on each lane.
2733
fn addr(self) -> Self::Usize;
2834

35+
/// Creates a new pointer with the given address.
36+
///
37+
/// This performs the same operation as a cast, but copies the *address-space* and
38+
/// *provenance* of `self` to the new pointer.
39+
///
40+
/// Equivalent to calling [`pointer::with_addr`] on each lane.
41+
fn with_addr(self, addr: Self::Usize) -> Self;
42+
2943
/// Calculates the offset from a pointer using wrapping arithmetic.
3044
///
3145
/// Equivalent to calling [`pointer::wrapping_offset`] on each lane.
@@ -63,12 +77,27 @@ where
6377

6478
#[inline]
6579
fn as_mut(self) -> Self::MutPtr {
66-
self.cast()
80+
unimplemented!()
81+
//self.cast()
6782
}
6883

6984
#[inline]
7085
fn addr(self) -> Self::Usize {
71-
self.cast()
86+
// Safety: Since `addr` discards provenance, this is safe.
87+
unsafe { core::mem::transmute_copy(&self) }
88+
89+
//TODO switch to casts when available
90+
//self.cast()
91+
}
92+
93+
#[inline]
94+
fn with_addr(self, addr: Self::Usize) -> Self {
95+
unimplemented!()
96+
/*
97+
self.cast::<*const u8>()
98+
.wrapping_offset(addr.cast::<isize>() - self.addr().cast::<isize>())
99+
.cast()
100+
*/
72101
}
73102

74103
#[inline]

crates/core_simd/src/elements/mut_ptr.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,20 @@ pub trait SimdMutPtr: Copy + Sealed {
2323

2424
/// Gets the "address" portion of the pointer.
2525
///
26+
/// This method discards pointer semantic metadata, so the result cannot be
27+
/// directly cast into a valid pointer.
28+
///
2629
/// Equivalent to calling [`pointer::addr`] on each lane.
2730
fn addr(self) -> Self::Usize;
2831

32+
/// Creates a new pointer with the given address.
33+
///
34+
/// This performs the same operation as a cast, but copies the *address-space* and
35+
/// *provenance* of `self` to the new pointer.
36+
///
37+
/// Equivalent to calling [`pointer::with_addr`] on each lane.
38+
fn with_addr(self, addr: Self::Usize) -> Self;
39+
2940
/// Calculates the offset from a pointer using wrapping arithmetic.
3041
///
3142
/// Equivalent to calling [`pointer::wrapping_offset`] on each lane.
@@ -61,12 +72,27 @@ where
6172

6273
#[inline]
6374
fn as_const(self) -> Self::ConstPtr {
64-
self.cast()
75+
unimplemented!()
76+
//self.cast()
6577
}
6678

6779
#[inline]
6880
fn addr(self) -> Self::Usize {
69-
self.cast()
81+
// Safety: Since `addr` discards provenance, this is safe.
82+
unsafe { core::mem::transmute_copy(&self) }
83+
84+
//TODO switch to casts when available
85+
//self.cast()
86+
}
87+
88+
#[inline]
89+
fn with_addr(self, addr: Self::Usize) -> Self {
90+
unimplemented!()
91+
/*
92+
self.cast::<*mut u8>()
93+
.wrapping_offset(addr.cast::<isize>() - self.addr().cast::<isize>())
94+
.cast()
95+
*/
7096
}
7197

7298
#[inline]

crates/core_simd/src/vector.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,9 +237,8 @@ where
237237
T: core::convert::FloatToInt<I> + SimdCast<I>,
238238
I: SimdElement,
239239
{
240-
// Safety: `self` is a vector, and `FloatToInt` ensures the type can be casted to
241-
// an integer.
242-
unsafe { intrinsics::simd_cast(self) }
240+
// Safety: the caller is responsible for the invariants
241+
unsafe { SimdCast::cast_unchecked(self) }
243242
}
244243

245244
/// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.

0 commit comments

Comments
 (0)