From e7cc021189f1d18974057d60223bdbb5abd4dc15 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 25 Jun 2022 00:00:20 -0400 Subject: [PATCH] Fix casts --- crates/core_simd/src/cast.rs | 158 +++++++-------------- crates/core_simd/src/elements/const_ptr.rs | 33 ++++- crates/core_simd/src/elements/mut_ptr.rs | 30 +++- crates/core_simd/src/vector.rs | 5 +- 4 files changed, 115 insertions(+), 111 deletions(-) diff --git a/crates/core_simd/src/cast.rs b/crates/core_simd/src/cast.rs index d62d3f6635d5..ddcc786afa44 100644 --- a/crates/core_simd/src/cast.rs +++ b/crates/core_simd/src/cast.rs @@ -1,129 +1,79 @@ use crate::simd::{intrinsics, LaneCount, Simd, SimdElement, SupportedLaneCount}; /// Supporting trait for `Simd::cast`. Typically doesn't need to be used directly. -pub trait SimdCast: SimdElement { +pub unsafe trait SimdCast: SimdElement { #[doc(hidden)] fn cast(x: Simd) -> Simd where - LaneCount: SupportedLaneCount; + LaneCount: SupportedLaneCount, + { + // Safety: implementing this trait indicates that the types are supported by `simd_as` + unsafe { intrinsics::simd_as(x) } + } + + #[doc(hidden)] + unsafe fn cast_unchecked(x: Simd) -> Simd + where + LaneCount: SupportedLaneCount, + { + // Safety: implementing this trait indicates that the types are supported by `simd_cast` + // The caller is responsible for the conversion invariants. + unsafe { intrinsics::simd_cast(x) } + } } macro_rules! into_number { - { $from:ty, $to:ty } => { - impl SimdCast<$to> for $from { - fn cast(x: Simd) -> Simd<$to, LANES> - where - LaneCount: SupportedLaneCount, - { - // Safety: simd_as can handle numeric conversions - unsafe { intrinsics::simd_as(x) } - } - } + { unsafe $from:ty as $to:ty } => { + // Safety: casting between numbers is supported by `simd_cast` and `simd_as` + unsafe impl SimdCast<$to> for $from {} }; - { $($type:ty),* } => { + { unsafe $($type:ty),* } => { $( - into_number! { $type, i8 } - into_number! { $type, i16 } - into_number! { $type, i32 } - into_number! { $type, i64 } - into_number! { $type, isize } + into_number! { unsafe $type as i8 } + into_number! { unsafe $type as i16 } + into_number! { unsafe $type as i32 } + into_number! { unsafe $type as i64 } + into_number! { unsafe $type as isize } - into_number! { $type, u8 } - into_number! { $type, u16 } - into_number! { $type, u32 } - into_number! { $type, u64 } - into_number! { $type, usize } + into_number! { unsafe $type as u8 } + into_number! { unsafe $type as u16 } + into_number! { unsafe $type as u32 } + into_number! { unsafe $type as u64 } + into_number! { unsafe $type as usize } - into_number! { $type, f32 } - into_number! { $type, f64 } + into_number! { unsafe $type as f32 } + into_number! { unsafe $type as f64 } )* } } -into_number! { i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64 } +into_number! { unsafe i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64 } +// TODO uncomment pending PR to rustc +/* macro_rules! into_pointer { - { $($type:ty),* } => { + { unsafe $($type:ty),* } => { $( - impl SimdCast<$type> for *const T { - fn cast(x: Simd) -> Simd<$type, LANES> - where - LaneCount: SupportedLaneCount, - { - // Safety: transmuting isize to pointers is safe - let x: Simd = unsafe { core::mem::transmute_copy(&x) }; - x.cast() - } - } - impl SimdCast<$type> for *mut T { - fn cast(x: Simd) -> Simd<$type, LANES> - where - LaneCount: SupportedLaneCount, - { - // Safety: transmuting isize to pointers is safe - let x: Simd = unsafe { core::mem::transmute_copy(&x) }; - x.cast() - } - } - impl SimdCast<*const T> for $type { - fn cast(x: Simd<$type, LANES>) -> Simd<*const T, LANES> - where - LaneCount: SupportedLaneCount, - { - let x: Simd = x.cast(); - // Safety: transmuting isize to pointers is safe - unsafe { core::mem::transmute_copy(&x) } - } - } - impl SimdCast<*mut T> for $type { - fn cast(x: Simd<$type, LANES>) -> Simd<*mut T, LANES> - where - LaneCount: SupportedLaneCount, - { - let x: Simd = x.cast(); - // Safety: transmuting isize to pointers is safe - unsafe { core::mem::transmute_copy(&x) } - } - } + // Safety: casting between numbers and pointers is supported by `simd_cast` and `simd_as` + unsafe impl SimdCast<$type> for *const T {} + // Safety: casting between numbers and pointers is supported by `simd_cast` and `simd_as` + unsafe impl SimdCast<$type> for *mut T {} + // Safety: casting between numbers and pointers is supported by `simd_cast` and `simd_as` + unsafe impl SimdCast<*const T> for $type {} + // Safety: casting between numbers and pointers is supported by `simd_cast` and `simd_as` + unsafe impl SimdCast<*mut T> for $type {} )* } } -into_pointer! { i8, i16, i32, i64, isize, u8, u16, u32, u64, usize } +into_pointer! { unsafe i8, i16, i32, i64, isize, u8, u16, u32, u64, usize } -impl SimdCast<*const T> for *const U { - fn cast(x: Simd<*const U, LANES>) -> Simd<*const T, LANES> - where - LaneCount: SupportedLaneCount, - { - // Safety: transmuting pointers is safe - unsafe { core::mem::transmute_copy(&x) } - } -} -impl SimdCast<*const T> for *mut U { - fn cast(x: Simd<*mut U, LANES>) -> Simd<*const T, LANES> - where - LaneCount: SupportedLaneCount, - { - // Safety: transmuting pointers is safe - unsafe { core::mem::transmute_copy(&x) } - } -} -impl SimdCast<*mut T> for *const U { - fn cast(x: Simd<*const U, LANES>) -> Simd<*mut T, LANES> - where - LaneCount: SupportedLaneCount, - { - // Safety: transmuting pointers is safe - unsafe { core::mem::transmute_copy(&x) } - } -} -impl SimdCast<*mut T> for *mut U { - fn cast(x: Simd<*mut U, LANES>) -> Simd<*mut T, LANES> - where - LaneCount: SupportedLaneCount, - { - // Safety: transmuting pointers is safe - unsafe { core::mem::transmute_copy(&x) } - } -} +// Safety: casting between pointers is supported by `simd_cast` and `simd_as` +unsafe impl SimdCast<*const T> for *const U {} +// Safety: casting between pointers is supported by `simd_cast` and `simd_as` +unsafe impl SimdCast<*const T> for *mut U {} +// Safety: casting between pointers is supported by `simd_cast` and `simd_as` +unsafe impl SimdCast<*mut T> for *const U {} +// Safety: casting between pointers is supported by `simd_cast` and `simd_as` +unsafe impl SimdCast<*mut T> for *mut U {} +*/ diff --git a/crates/core_simd/src/elements/const_ptr.rs b/crates/core_simd/src/elements/const_ptr.rs index d10bd1481d06..5a5faad23c81 100644 --- a/crates/core_simd/src/elements/const_ptr.rs +++ b/crates/core_simd/src/elements/const_ptr.rs @@ -23,9 +23,23 @@ pub trait SimdConstPtr: Copy + Sealed { /// Gets the "address" portion of the pointer. /// + /// This method discards pointer semantic metadata, so the result cannot be + /// directly cast into a valid pointer. + /// + /// This method semantically discards *provenance* and + /// *address-space* information. To properly restore that information, use [`with_addr`]. + /// /// Equivalent to calling [`pointer::addr`] on each lane. fn addr(self) -> Self::Usize; + /// Creates a new pointer with the given address. + /// + /// This performs the same operation as a cast, but copies the *address-space* and + /// *provenance* of `self` to the new pointer. + /// + /// Equivalent to calling [`pointer::with_addr`] on each lane. + fn with_addr(self, addr: Self::Usize) -> Self; + /// Calculates the offset from a pointer using wrapping arithmetic. /// /// Equivalent to calling [`pointer::wrapping_offset`] on each lane. @@ -63,12 +77,27 @@ where #[inline] fn as_mut(self) -> Self::MutPtr { - self.cast() + unimplemented!() + //self.cast() } #[inline] fn addr(self) -> Self::Usize { - self.cast() + // Safety: Since `addr` discards provenance, this is safe. + unsafe { core::mem::transmute_copy(&self) } + + //TODO switch to casts when available + //self.cast() + } + + #[inline] + fn with_addr(self, addr: Self::Usize) -> Self { + unimplemented!() + /* + self.cast::<*const u8>() + .wrapping_offset(addr.cast::() - self.addr().cast::()) + .cast() + */ } #[inline] diff --git a/crates/core_simd/src/elements/mut_ptr.rs b/crates/core_simd/src/elements/mut_ptr.rs index 4fc6202e14ef..d7b05af0eac5 100644 --- a/crates/core_simd/src/elements/mut_ptr.rs +++ b/crates/core_simd/src/elements/mut_ptr.rs @@ -23,9 +23,20 @@ pub trait SimdMutPtr: Copy + Sealed { /// Gets the "address" portion of the pointer. /// + /// This method discards pointer semantic metadata, so the result cannot be + /// directly cast into a valid pointer. + /// /// Equivalent to calling [`pointer::addr`] on each lane. fn addr(self) -> Self::Usize; + /// Creates a new pointer with the given address. + /// + /// This performs the same operation as a cast, but copies the *address-space* and + /// *provenance* of `self` to the new pointer. + /// + /// Equivalent to calling [`pointer::with_addr`] on each lane. + fn with_addr(self, addr: Self::Usize) -> Self; + /// Calculates the offset from a pointer using wrapping arithmetic. /// /// Equivalent to calling [`pointer::wrapping_offset`] on each lane. @@ -61,12 +72,27 @@ where #[inline] fn as_const(self) -> Self::ConstPtr { - self.cast() + unimplemented!() + //self.cast() } #[inline] fn addr(self) -> Self::Usize { - self.cast() + // Safety: Since `addr` discards provenance, this is safe. + unsafe { core::mem::transmute_copy(&self) } + + //TODO switch to casts when available + //self.cast() + } + + #[inline] + fn with_addr(self, addr: Self::Usize) -> Self { + unimplemented!() + /* + self.cast::<*mut u8>() + .wrapping_offset(addr.cast::() - self.addr().cast::()) + .cast() + */ } #[inline] diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs index 2fc090254d74..3987b7a747b6 100644 --- a/crates/core_simd/src/vector.rs +++ b/crates/core_simd/src/vector.rs @@ -237,9 +237,8 @@ where T: core::convert::FloatToInt + SimdCast, I: SimdElement, { - // Safety: `self` is a vector, and `FloatToInt` ensures the type can be casted to - // an integer. - unsafe { intrinsics::simd_cast(self) } + // Safety: the caller is responsible for the invariants + unsafe { SimdCast::cast_unchecked(self) } } /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.