Fix casts

This commit is contained in:
Caleb Zulawski 2022-06-25 00:00:20 -04:00
parent da25087f79
commit e7cc021189
4 changed files with 115 additions and 111 deletions

View file

@ -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 {}
*/

View file

@ -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]

View file

@ -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]

View file

@ -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.