Skip to content

Commit fd68a6d

Browse files
committed
Auto merge of #113437 - workingjubilee:sync-simd-2023-july-07, r=workingjubilee
Sync portable-simd to 2023 July 07 r? `@ghost`
2 parents 1a449dc + 37fea34 commit fd68a6d

File tree

19 files changed

+339
-134
lines changed

19 files changed

+339
-134
lines changed

library/portable-simd/.github/workflows/ci.yml

+5-4
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ jobs:
3838
- i586-unknown-linux-gnu
3939
- aarch64-unknown-linux-gnu
4040
- armv7-unknown-linux-gnueabihf
41-
- mips-unknown-linux-gnu
42-
- mips64-unknown-linux-gnuabi64
41+
# non-nightly since https://github.com/rust-lang/rust/pull/113274
42+
# - mips-unknown-linux-gnu
43+
# - mips64-unknown-linux-gnuabi64
4344
- powerpc-unknown-linux-gnu
4445
- powerpc64-unknown-linux-gnu
4546
- riscv64gc-unknown-linux-gnu
@@ -191,8 +192,8 @@ jobs:
191192
# Note: The issue above means neither of these mips targets will use
192193
# MSA (mips simd) but MIPS uses a nonstandard binary representation
193194
# for NaNs which makes it worth testing on despite that.
194-
- mips-unknown-linux-gnu
195-
- mips64-unknown-linux-gnuabi64
195+
# - mips-unknown-linux-gnu
196+
# - mips64-unknown-linux-gnuabi64
196197
- riscv64gc-unknown-linux-gnu
197198
# TODO this test works, but it appears to time out
198199
# - powerpc-unknown-linux-gnu
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,51 @@
11
use crate::simd::SimdElement;
22

3+
mod sealed {
4+
/// Cast vector elements to other types.
5+
///
6+
/// # Safety
7+
/// Implementing this trait asserts that the type is a valid vector element for the `simd_cast`
8+
/// or `simd_as` intrinsics.
9+
pub unsafe trait Sealed {}
10+
}
11+
use sealed::Sealed;
12+
313
/// Supporting trait for `Simd::cast`. Typically doesn't need to be used directly.
4-
///
5-
/// # Safety
6-
/// Implementing this trait asserts that the type is a valid vector element for the `simd_cast` or
7-
/// `simd_as` intrinsics.
8-
pub unsafe trait SimdCast: SimdElement {}
14+
pub trait SimdCast: Sealed + SimdElement {}
915

1016
// Safety: primitive number types can be cast to other primitive number types
11-
unsafe impl SimdCast for i8 {}
17+
unsafe impl Sealed for i8 {}
18+
impl SimdCast for i8 {}
1219
// Safety: primitive number types can be cast to other primitive number types
13-
unsafe impl SimdCast for i16 {}
20+
unsafe impl Sealed for i16 {}
21+
impl SimdCast for i16 {}
1422
// Safety: primitive number types can be cast to other primitive number types
15-
unsafe impl SimdCast for i32 {}
23+
unsafe impl Sealed for i32 {}
24+
impl SimdCast for i32 {}
1625
// Safety: primitive number types can be cast to other primitive number types
17-
unsafe impl SimdCast for i64 {}
26+
unsafe impl Sealed for i64 {}
27+
impl SimdCast for i64 {}
1828
// Safety: primitive number types can be cast to other primitive number types
19-
unsafe impl SimdCast for isize {}
29+
unsafe impl Sealed for isize {}
30+
impl SimdCast for isize {}
2031
// Safety: primitive number types can be cast to other primitive number types
21-
unsafe impl SimdCast for u8 {}
32+
unsafe impl Sealed for u8 {}
33+
impl SimdCast for u8 {}
2234
// Safety: primitive number types can be cast to other primitive number types
23-
unsafe impl SimdCast for u16 {}
35+
unsafe impl Sealed for u16 {}
36+
impl SimdCast for u16 {}
2437
// Safety: primitive number types can be cast to other primitive number types
25-
unsafe impl SimdCast for u32 {}
38+
unsafe impl Sealed for u32 {}
39+
impl SimdCast for u32 {}
2640
// Safety: primitive number types can be cast to other primitive number types
27-
unsafe impl SimdCast for u64 {}
41+
unsafe impl Sealed for u64 {}
42+
impl SimdCast for u64 {}
2843
// Safety: primitive number types can be cast to other primitive number types
29-
unsafe impl SimdCast for usize {}
44+
unsafe impl Sealed for usize {}
45+
impl SimdCast for usize {}
3046
// Safety: primitive number types can be cast to other primitive number types
31-
unsafe impl SimdCast for f32 {}
47+
unsafe impl Sealed for f32 {}
48+
impl SimdCast for f32 {}
3249
// Safety: primitive number types can be cast to other primitive number types
33-
unsafe impl SimdCast for f64 {}
34-
35-
/// Supporting trait for `Simd::cast_ptr`. Typically doesn't need to be used directly.
36-
///
37-
/// # Safety
38-
/// Implementing this trait asserts that the type is a valid vector element for the `simd_cast_ptr`
39-
/// intrinsic.
40-
pub unsafe trait SimdCastPtr<T> {}
41-
42-
// Safety: pointers can be cast to other pointer types
43-
unsafe impl<T, U> SimdCastPtr<T> for *const U
44-
where
45-
U: core::ptr::Pointee,
46-
T: core::ptr::Pointee<Metadata = U::Metadata>,
47-
{
48-
}
49-
// Safety: pointers can be cast to other pointer types
50-
unsafe impl<T, U> SimdCastPtr<T> for *mut U
51-
where
52-
U: core::ptr::Pointee,
53-
T: core::ptr::Pointee<Metadata = U::Metadata>,
54-
{
55-
}
50+
unsafe impl Sealed for f64 {}
51+
impl SimdCast for f64 {}

library/portable-simd/crates/core_simd/src/elements/const_ptr.rs

+26-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::sealed::Sealed;
2-
use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount};
2+
use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SimdUint, SupportedLaneCount};
33

44
/// Operations on SIMD vectors of constant pointers.
55
pub trait SimdConstPtr: Copy + Sealed {
@@ -9,6 +9,9 @@ pub trait SimdConstPtr: Copy + Sealed {
99
/// Vector of `isize` with the same number of lanes.
1010
type Isize;
1111

12+
/// Vector of const pointers with the same number of lanes.
13+
type CastPtr<T>;
14+
1215
/// Vector of mutable pointers to the same type.
1316
type MutPtr;
1417

@@ -18,6 +21,11 @@ pub trait SimdConstPtr: Copy + Sealed {
1821
/// Returns `true` for each lane that is null.
1922
fn is_null(self) -> Self::Mask;
2023

24+
/// Casts to a pointer of another type.
25+
///
26+
/// Equivalent to calling [`pointer::cast`] on each lane.
27+
fn cast<T>(self) -> Self::CastPtr<T>;
28+
2129
/// Changes constness without changing the type.
2230
///
2331
/// Equivalent to calling [`pointer::cast_mut`] on each lane.
@@ -78,6 +86,7 @@ where
7886
{
7987
type Usize = Simd<usize, LANES>;
8088
type Isize = Simd<isize, LANES>;
89+
type CastPtr<U> = Simd<*const U, LANES>;
8190
type MutPtr = Simd<*mut T, LANES>;
8291
type Mask = Mask<isize, LANES>;
8392

@@ -86,9 +95,22 @@ where
8695
Simd::splat(core::ptr::null()).simd_eq(self)
8796
}
8897

98+
#[inline]
99+
fn cast<U>(self) -> Self::CastPtr<U> {
100+
// SimdElement currently requires zero-sized metadata, so this should never fail.
101+
// If this ever changes, `simd_cast_ptr` should produce a post-mono error.
102+
use core::{mem::size_of, ptr::Pointee};
103+
assert_eq!(size_of::<<T as Pointee>::Metadata>(), 0);
104+
assert_eq!(size_of::<<U as Pointee>::Metadata>(), 0);
105+
106+
// Safety: pointers can be cast
107+
unsafe { intrinsics::simd_cast_ptr(self) }
108+
}
109+
89110
#[inline]
90111
fn cast_mut(self) -> Self::MutPtr {
91-
self.cast_ptr()
112+
// Safety: pointers can be cast
113+
unsafe { intrinsics::simd_cast_ptr(self) }
92114
}
93115

94116
#[inline]
@@ -106,9 +128,9 @@ where
106128
// In the mean-time, this operation is defined to be "as if" it was
107129
// a wrapping_offset, so we can emulate it as such. This should properly
108130
// restore pointer provenance even under today's compiler.
109-
self.cast_ptr::<*const u8>()
131+
self.cast::<u8>()
110132
.wrapping_offset(addr.cast::<isize>() - self.addr().cast::<isize>())
111-
.cast_ptr()
133+
.cast()
112134
}
113135

114136
#[inline]

library/portable-simd/crates/core_simd/src/elements/float.rs

+66-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::sealed::Sealed;
22
use crate::simd::{
3-
intrinsics, LaneCount, Mask, Simd, SimdElement, SimdPartialEq, SimdPartialOrd,
3+
intrinsics, LaneCount, Mask, Simd, SimdCast, SimdElement, SimdPartialEq, SimdPartialOrd,
44
SupportedLaneCount,
55
};
66

@@ -15,6 +15,53 @@ pub trait SimdFloat: Copy + Sealed {
1515
/// Bit representation of this SIMD vector type.
1616
type Bits;
1717

18+
/// A SIMD vector with a different element type.
19+
type Cast<T: SimdElement>;
20+
21+
/// Performs elementwise conversion of this vector's elements to another SIMD-valid type.
22+
///
23+
/// This follows the semantics of Rust's `as` conversion for floats (truncating or saturating
24+
/// at the limits) for each element.
25+
///
26+
/// # Example
27+
/// ```
28+
/// # #![feature(portable_simd)]
29+
/// # #[cfg(feature = "as_crate")] use core_simd::simd;
30+
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
31+
/// # use simd::{SimdFloat, SimdInt, Simd};
32+
/// let floats: Simd<f32, 4> = Simd::from_array([1.9, -4.5, f32::INFINITY, f32::NAN]);
33+
/// let ints = floats.cast::<i32>();
34+
/// assert_eq!(ints, Simd::from_array([1, -4, i32::MAX, 0]));
35+
///
36+
/// // Formally equivalent, but `Simd::cast` can optimize better.
37+
/// assert_eq!(ints, Simd::from_array(floats.to_array().map(|x| x as i32)));
38+
///
39+
/// // The float conversion does not round-trip.
40+
/// let floats_again = ints.cast();
41+
/// assert_ne!(floats, floats_again);
42+
/// assert_eq!(floats_again, Simd::from_array([1.0, -4.0, 2147483647.0, 0.0]));
43+
/// ```
44+
#[must_use]
45+
fn cast<T: SimdCast>(self) -> Self::Cast<T>;
46+
47+
/// Rounds toward zero and converts to the same-width integer type, assuming that
48+
/// the value is finite and fits in that type.
49+
///
50+
/// # Safety
51+
/// The value must:
52+
///
53+
/// * Not be NaN
54+
/// * Not be infinite
55+
/// * Be representable in the return type, after truncating off its fractional part
56+
///
57+
/// If these requirements are infeasible or costly, consider using the safe function [cast],
58+
/// which saturates on conversion.
59+
///
60+
/// [cast]: Simd::cast
61+
unsafe fn to_int_unchecked<I: SimdCast>(self) -> Self::Cast<I>
62+
where
63+
Self::Scalar: core::convert::FloatToInt<I>;
64+
1865
/// Raw transmutation to an unsigned integer vector type with the
1966
/// same size and number of lanes.
2067
#[must_use = "method returns a new vector and does not mutate the original value"]
@@ -206,6 +253,24 @@ macro_rules! impl_trait {
206253
type Mask = Mask<<$mask_ty as SimdElement>::Mask, LANES>;
207254
type Scalar = $ty;
208255
type Bits = Simd<$bits_ty, LANES>;
256+
type Cast<T: SimdElement> = Simd<T, LANES>;
257+
258+
#[inline]
259+
fn cast<T: SimdCast>(self) -> Self::Cast<T>
260+
{
261+
// Safety: supported types are guaranteed by SimdCast
262+
unsafe { intrinsics::simd_as(self) }
263+
}
264+
265+
#[inline]
266+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
267+
unsafe fn to_int_unchecked<I: SimdCast>(self) -> Self::Cast<I>
268+
where
269+
Self::Scalar: core::convert::FloatToInt<I>,
270+
{
271+
// Safety: supported types are guaranteed by SimdCast, the caller is responsible for the extra invariants
272+
unsafe { intrinsics::simd_cast(self) }
273+
}
209274

210275
#[inline]
211276
fn to_bits(self) -> Simd<$bits_ty, LANES> {

library/portable-simd/crates/core_simd/src/elements/int.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::sealed::Sealed;
22
use crate::simd::{
3-
intrinsics, LaneCount, Mask, Simd, SimdElement, SimdPartialOrd, SupportedLaneCount,
3+
intrinsics, LaneCount, Mask, Simd, SimdCast, SimdElement, SimdPartialOrd, SupportedLaneCount,
44
};
55

66
/// Operations on SIMD vectors of signed integers.
@@ -11,6 +11,16 @@ pub trait SimdInt: Copy + Sealed {
1111
/// Scalar type contained by this SIMD vector type.
1212
type Scalar;
1313

14+
/// A SIMD vector with a different element type.
15+
type Cast<T: SimdElement>;
16+
17+
/// Performs elementwise conversion of this vector's elements to another SIMD-valid type.
18+
///
19+
/// This follows the semantics of Rust's `as` conversion for casting integers (wrapping to
20+
/// other integer types, and saturating to float types).
21+
#[must_use]
22+
fn cast<T: SimdCast>(self) -> Self::Cast<T>;
23+
1424
/// Lanewise saturating add.
1525
///
1626
/// # Examples
@@ -198,6 +208,13 @@ macro_rules! impl_trait {
198208
{
199209
type Mask = Mask<<$ty as SimdElement>::Mask, LANES>;
200210
type Scalar = $ty;
211+
type Cast<T: SimdElement> = Simd<T, LANES>;
212+
213+
#[inline]
214+
fn cast<T: SimdCast>(self) -> Self::Cast<T> {
215+
// Safety: supported types are guaranteed by SimdCast
216+
unsafe { intrinsics::simd_as(self) }
217+
}
201218

202219
#[inline]
203220
fn saturating_add(self, second: Self) -> Self {

library/portable-simd/crates/core_simd/src/elements/mut_ptr.rs

+26-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::sealed::Sealed;
2-
use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount};
2+
use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SimdUint, SupportedLaneCount};
33

44
/// Operations on SIMD vectors of mutable pointers.
55
pub trait SimdMutPtr: Copy + Sealed {
@@ -9,6 +9,9 @@ pub trait SimdMutPtr: Copy + Sealed {
99
/// Vector of `isize` with the same number of lanes.
1010
type Isize;
1111

12+
/// Vector of const pointers with the same number of lanes.
13+
type CastPtr<T>;
14+
1215
/// Vector of constant pointers to the same type.
1316
type ConstPtr;
1417

@@ -18,6 +21,11 @@ pub trait SimdMutPtr: Copy + Sealed {
1821
/// Returns `true` for each lane that is null.
1922
fn is_null(self) -> Self::Mask;
2023

24+
/// Casts to a pointer of another type.
25+
///
26+
/// Equivalent to calling [`pointer::cast`] on each lane.
27+
fn cast<T>(self) -> Self::CastPtr<T>;
28+
2129
/// Changes constness without changing the type.
2230
///
2331
/// Equivalent to calling [`pointer::cast_const`] on each lane.
@@ -73,6 +81,7 @@ where
7381
{
7482
type Usize = Simd<usize, LANES>;
7583
type Isize = Simd<isize, LANES>;
84+
type CastPtr<U> = Simd<*mut U, LANES>;
7685
type ConstPtr = Simd<*const T, LANES>;
7786
type Mask = Mask<isize, LANES>;
7887

@@ -81,9 +90,22 @@ where
8190
Simd::splat(core::ptr::null_mut()).simd_eq(self)
8291
}
8392

93+
#[inline]
94+
fn cast<U>(self) -> Self::CastPtr<U> {
95+
// SimdElement currently requires zero-sized metadata, so this should never fail.
96+
// If this ever changes, `simd_cast_ptr` should produce a post-mono error.
97+
use core::{mem::size_of, ptr::Pointee};
98+
assert_eq!(size_of::<<T as Pointee>::Metadata>(), 0);
99+
assert_eq!(size_of::<<U as Pointee>::Metadata>(), 0);
100+
101+
// Safety: pointers can be cast
102+
unsafe { intrinsics::simd_cast_ptr(self) }
103+
}
104+
84105
#[inline]
85106
fn cast_const(self) -> Self::ConstPtr {
86-
self.cast_ptr()
107+
// Safety: pointers can be cast
108+
unsafe { intrinsics::simd_cast_ptr(self) }
87109
}
88110

89111
#[inline]
@@ -101,9 +123,9 @@ where
101123
// In the mean-time, this operation is defined to be "as if" it was
102124
// a wrapping_offset, so we can emulate it as such. This should properly
103125
// restore pointer provenance even under today's compiler.
104-
self.cast_ptr::<*mut u8>()
126+
self.cast::<u8>()
105127
.wrapping_offset(addr.cast::<isize>() - self.addr().cast::<isize>())
106-
.cast_ptr()
128+
.cast()
107129
}
108130

109131
#[inline]

0 commit comments

Comments
 (0)