Fix casts
This commit is contained in:
parent
da25087f79
commit
e7cc021189
4 changed files with 115 additions and 111 deletions
|
|
@ -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 {}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue