about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCaleb Zulawski <caleb.zulawski@gmail.com>2022-06-25 00:00:20 -0400
committerCaleb Zulawski <caleb.zulawski@gmail.com>2022-10-29 11:55:01 -0400
commite7cc021189f1d18974057d60223bdbb5abd4dc15 (patch)
treea5b8829715b9fd88ac2e75cad9834ac032baeab9
parentda25087f790e9c15fcf633a39e5de307608c9251 (diff)
downloadrust-e7cc021189f1d18974057d60223bdbb5abd4dc15.tar.gz
rust-e7cc021189f1d18974057d60223bdbb5abd4dc15.zip
Fix casts
-rw-r--r--crates/core_simd/src/cast.rs158
-rw-r--r--crates/core_simd/src/elements/const_ptr.rs33
-rw-r--r--crates/core_simd/src/elements/mut_ptr.rs30
-rw-r--r--crates/core_simd/src/vector.rs5
4 files changed, 115 insertions, 111 deletions
diff --git a/crates/core_simd/src/cast.rs b/crates/core_simd/src/cast.rs
index d62d3f6635d..ddcc786afa4 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<Target: SimdElement>: SimdElement {
+pub unsafe trait SimdCast<Target: SimdElement>: SimdElement {
     #[doc(hidden)]
     fn cast<const LANES: usize>(x: Simd<Self, LANES>) -> Simd<Target, LANES>
     where
-        LaneCount<LANES>: SupportedLaneCount;
+        LaneCount<LANES>: 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<const LANES: usize>(x: Simd<Self, LANES>) -> Simd<Target, LANES>
+    where
+        LaneCount<LANES>: 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<const LANES: usize>(x: Simd<Self, LANES>) -> Simd<$to, LANES>
-            where
-                LaneCount<LANES>: 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<T> SimdCast<$type> for *const T {
-            fn cast<const LANES: usize>(x: Simd<Self, LANES>) -> Simd<$type, LANES>
-            where
-                LaneCount<LANES>: SupportedLaneCount,
-            {
-                // Safety: transmuting isize to pointers is safe
-                let x: Simd<isize, LANES> = unsafe { core::mem::transmute_copy(&x) };
-                x.cast()
-            }
-        }
-        impl<T> SimdCast<$type> for *mut T {
-            fn cast<const LANES: usize>(x: Simd<Self, LANES>) -> Simd<$type, LANES>
-            where
-                LaneCount<LANES>: SupportedLaneCount,
-            {
-                // Safety: transmuting isize to pointers is safe
-                let x: Simd<isize, LANES> = unsafe { core::mem::transmute_copy(&x) };
-                x.cast()
-            }
-        }
-        impl<T> SimdCast<*const T> for $type {
-            fn cast<const LANES: usize>(x: Simd<$type, LANES>) -> Simd<*const T, LANES>
-            where
-                LaneCount<LANES>: SupportedLaneCount,
-            {
-                let x: Simd<isize, LANES> = x.cast();
-                // Safety: transmuting isize to pointers is safe
-                unsafe { core::mem::transmute_copy(&x) }
-            }
-        }
-        impl<T> SimdCast<*mut T> for $type {
-            fn cast<const LANES: usize>(x: Simd<$type, LANES>) -> Simd<*mut T, LANES>
-            where
-                LaneCount<LANES>: SupportedLaneCount,
-            {
-                let x: Simd<isize, LANES> = 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<T> SimdCast<$type> for *const T {}
+        // Safety: casting between numbers and pointers is supported by `simd_cast` and `simd_as`
+        unsafe impl<T> SimdCast<$type> for *mut T {}
+        // Safety: casting between numbers and pointers is supported by `simd_cast` and `simd_as`
+        unsafe impl<T> SimdCast<*const T> for $type {}
+        // Safety: casting between numbers and pointers is supported by `simd_cast` and `simd_as`
+        unsafe impl<T> 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<T, U> SimdCast<*const T> for *const U {
-    fn cast<const LANES: usize>(x: Simd<*const U, LANES>) -> Simd<*const T, LANES>
-    where
-        LaneCount<LANES>: SupportedLaneCount,
-    {
-        // Safety: transmuting pointers is safe
-        unsafe { core::mem::transmute_copy(&x) }
-    }
-}
-impl<T, U> SimdCast<*const T> for *mut U {
-    fn cast<const LANES: usize>(x: Simd<*mut U, LANES>) -> Simd<*const T, LANES>
-    where
-        LaneCount<LANES>: SupportedLaneCount,
-    {
-        // Safety: transmuting pointers is safe
-        unsafe { core::mem::transmute_copy(&x) }
-    }
-}
-impl<T, U> SimdCast<*mut T> for *const U {
-    fn cast<const LANES: usize>(x: Simd<*const U, LANES>) -> Simd<*mut T, LANES>
-    where
-        LaneCount<LANES>: SupportedLaneCount,
-    {
-        // Safety: transmuting pointers is safe
-        unsafe { core::mem::transmute_copy(&x) }
-    }
-}
-impl<T, U> SimdCast<*mut T> for *mut U {
-    fn cast<const LANES: usize>(x: Simd<*mut U, LANES>) -> Simd<*mut T, LANES>
-    where
-        LaneCount<LANES>: 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<T, U> SimdCast<*const T> for *const U {}
+// Safety: casting between pointers is supported by `simd_cast` and `simd_as`
+unsafe impl<T, U> SimdCast<*const T> for *mut U {}
+// Safety: casting between pointers is supported by `simd_cast` and `simd_as`
+unsafe impl<T, U> SimdCast<*mut T> for *const U {}
+// Safety: casting between pointers is supported by `simd_cast` and `simd_as`
+unsafe impl<T, U> 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 d10bd1481d0..5a5faad23c8 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::<isize>() - self.addr().cast::<isize>())
+            .cast()
+        */
     }
 
     #[inline]
diff --git a/crates/core_simd/src/elements/mut_ptr.rs b/crates/core_simd/src/elements/mut_ptr.rs
index 4fc6202e14e..d7b05af0eac 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::<isize>() - self.addr().cast::<isize>())
+            .cast()
+        */
     }
 
     #[inline]
diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs
index 2fc090254d7..3987b7a747b 100644
--- a/crates/core_simd/src/vector.rs
+++ b/crates/core_simd/src/vector.rs
@@ -237,9 +237,8 @@ where
         T: core::convert::FloatToInt<I> + SimdCast<I>,
         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.