Skip to content

Commit 11fb21f

Browse files
committedDec 8, 2021
Auto merge of #91484 - workingjubilee:simd-remove-autosplats, r=Mark-Simulacrum
Sync portable-simd to remove autosplats This PR syncs portable-simd in up to rust-lang/portable-simd@a838552 in order to address the type inference breakages documented on nightly in #90904 by removing the vector + scalar binary operations (called "autosplats", "broadcasting", or "rank promotion", depending on who you ask) that allow `{scalar} + &'_ {scalar}` to fail in some cases, because it becomes possible the programmer may have meant `{scalar} + &'_ {vector}`. A few quality-of-life improvements make their way in as well: - Lane counts can now go to 64, as LLVM seems to have fixed their miscompilation for those. - `{i,u}8x64` to `__m512i` is now available. - a bunch of `#[must_use]` notes appear throughout the module. - Some implementations, mostly instances of `impl core::ops::{Op}<Simd> for Simd` that aren't `{vector} + {vector}` (e.g. `{vector} + &'_ {vector}`), leverage some generics and `where` bounds now to make them easier to understand by reducing a dozen implementations into one (and make it possible for people to open the docs on less burly devices). - And some internal-only improvements. None of these changes should affect a beta backport, only actual users of `core::simd` (and most aren't even visible in the programmatic sense), though I can extract an even more minimal changeset for beta if necessary. It seemed simpler to just keep moving forward.
2 parents 477fd70 + eef4371 commit 11fb21f

File tree

23 files changed

+540
-525
lines changed

23 files changed

+540
-525
lines changed
 

‎library/core/tests/simd.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ fn testing() {
77
let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]);
88
let y = -x;
99

10-
let h = x * 0.5;
10+
let h = x * f32x4::splat(0.5);
1111

1212
let r = y.abs();
1313
assert_eq!(x, r);

‎library/portable-simd/CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ SIMD can be quite complex, and even a "simple" issue can be huge. If an issue is
1515

1616
## CI
1717

18-
We currently have 2 CI matrices through Travis CI and GitHub Actions that will automatically build and test your change in order to verify that `std::simd`'s portable API is, in fact, portable. If your change builds locally, but does not build on either, this is likely due to a platform-specific concern that your code has not addressed. Please consult the build logs and address the error, or ask for help if you need it.
18+
We currently use GitHub Actions which will automatically build and test your change in order to verify that `std::simd`'s portable API is, in fact, portable. If your change builds locally, but does not build in CI, this is likely due to a platform-specific concern that your code has not addressed. Please consult the build logs and address the error, or ask for help if you need it.
1919

2020
## Beyond stdsimd
2121

‎library/portable-simd/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# The Rust standard library's portable SIMD API
2-
[![Build Status](https://travis-ci.com/rust-lang/portable-simd.svg?branch=master)](https://travis-ci.com/rust-lang/portable-simd)
2+
![Build Status](https://github.com/rust-lang/portable-simd/actions/workflows/ci.yml/badge.svg?branch=master)
33

44
Code repository for the [Portable SIMD Project Group](https://github.com/rust-lang/project-portable-simd).
55
Please refer to [CONTRIBUTING.md](./CONTRIBUTING.md) for our contributing guidelines.

‎library/portable-simd/crates/core_simd/examples/nbody.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ mod nbody {
9797
let sun = &mut sun[0];
9898
for body in rest {
9999
let m_ratio = body.mass / SOLAR_MASS;
100-
sun.v -= body.v * m_ratio;
100+
sun.v -= body.v * Simd::splat(m_ratio);
101101
}
102102
}
103103

@@ -143,14 +143,14 @@ mod nbody {
143143
let mut i = 0;
144144
for j in 0..N_BODIES {
145145
for k in j + 1..N_BODIES {
146-
let f = r[i] * mag[i];
147-
bodies[j].v -= f * bodies[k].mass;
148-
bodies[k].v += f * bodies[j].mass;
146+
let f = r[i] * Simd::splat(mag[i]);
147+
bodies[j].v -= f * Simd::splat(bodies[k].mass);
148+
bodies[k].v += f * Simd::splat(bodies[j].mass);
149149
i += 1
150150
}
151151
}
152152
for body in bodies {
153-
body.x += dt * body.v
153+
body.x += Simd::splat(dt) * body.v
154154
}
155155
}
156156

‎library/portable-simd/crates/core_simd/src/comparisons.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ where
88
{
99
/// Test if each lane is equal to the corresponding lane in `other`.
1010
#[inline]
11+
#[must_use = "method returns a new mask and does not mutate the original value"]
1112
pub fn lanes_eq(self, other: Self) -> Mask<T::Mask, LANES> {
1213
unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) }
1314
}
1415

1516
/// Test if each lane is not equal to the corresponding lane in `other`.
1617
#[inline]
18+
#[must_use = "method returns a new mask and does not mutate the original value"]
1719
pub fn lanes_ne(self, other: Self) -> Mask<T::Mask, LANES> {
1820
unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) }
1921
}
@@ -26,24 +28,28 @@ where
2628
{
2729
/// Test if each lane is less than the corresponding lane in `other`.
2830
#[inline]
31+
#[must_use = "method returns a new mask and does not mutate the original value"]
2932
pub fn lanes_lt(self, other: Self) -> Mask<T::Mask, LANES> {
3033
unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
3134
}
3235

3336
/// Test if each lane is greater than the corresponding lane in `other`.
3437
#[inline]
38+
#[must_use = "method returns a new mask and does not mutate the original value"]
3539
pub fn lanes_gt(self, other: Self) -> Mask<T::Mask, LANES> {
3640
unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
3741
}
3842

3943
/// Test if each lane is less than or equal to the corresponding lane in `other`.
4044
#[inline]
45+
#[must_use = "method returns a new mask and does not mutate the original value"]
4146
pub fn lanes_le(self, other: Self) -> Mask<T::Mask, LANES> {
4247
unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
4348
}
4449

4550
/// Test if each lane is greater than or equal to the corresponding lane in `other`.
4651
#[inline]
52+
#[must_use = "method returns a new mask and does not mutate the original value"]
4753
pub fn lanes_ge(self, other: Self) -> Mask<T::Mask, LANES> {
4854
unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
4955
}

‎library/portable-simd/crates/core_simd/src/lane_count.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,28 @@ impl<const LANES: usize> LaneCount<LANES> {
1515
pub trait SupportedLaneCount: Sealed {
1616
#[doc(hidden)]
1717
type BitMask: Copy + Default + AsRef<[u8]> + AsMut<[u8]>;
18-
19-
#[doc(hidden)]
20-
type IntBitMask;
2118
}
2219

2320
impl<const LANES: usize> Sealed for LaneCount<LANES> {}
2421

2522
impl SupportedLaneCount for LaneCount<1> {
2623
type BitMask = [u8; 1];
27-
type IntBitMask = u8;
2824
}
2925
impl SupportedLaneCount for LaneCount<2> {
3026
type BitMask = [u8; 1];
31-
type IntBitMask = u8;
3227
}
3328
impl SupportedLaneCount for LaneCount<4> {
3429
type BitMask = [u8; 1];
35-
type IntBitMask = u8;
3630
}
3731
impl SupportedLaneCount for LaneCount<8> {
3832
type BitMask = [u8; 1];
39-
type IntBitMask = u8;
4033
}
4134
impl SupportedLaneCount for LaneCount<16> {
4235
type BitMask = [u8; 2];
43-
type IntBitMask = u16;
4436
}
4537
impl SupportedLaneCount for LaneCount<32> {
4638
type BitMask = [u8; 4];
47-
type IntBitMask = u32;
39+
}
40+
impl SupportedLaneCount for LaneCount<64> {
41+
type BitMask = [u8; 8];
4842
}

‎library/portable-simd/crates/core_simd/src/masks.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ where
129129
/// # Safety
130130
/// All lanes must be either 0 or -1.
131131
#[inline]
132+
#[must_use = "method returns a new mask and does not mutate the original value"]
132133
pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self {
133134
unsafe { Self(mask_impl::Mask::from_int_unchecked(value)) }
134135
}
@@ -139,6 +140,7 @@ where
139140
/// # Panics
140141
/// Panics if any lane is not 0 or -1.
141142
#[inline]
143+
#[must_use = "method returns a new mask and does not mutate the original value"]
142144
pub fn from_int(value: Simd<T, LANES>) -> Self {
143145
assert!(T::valid(value), "all values must be either 0 or -1",);
144146
unsafe { Self::from_int_unchecked(value) }
@@ -147,6 +149,7 @@ where
147149
/// Converts the mask to a vector of integers, where 0 represents `false` and -1
148150
/// represents `true`.
149151
#[inline]
152+
#[must_use = "method returns a new vector and does not mutate the original value"]
150153
pub fn to_int(self) -> Simd<T, LANES> {
151154
self.0.to_int()
152155
}
@@ -156,6 +159,7 @@ where
156159
/// # Safety
157160
/// `lane` must be less than `LANES`.
158161
#[inline]
162+
#[must_use = "method returns a new bool and does not mutate the original value"]
159163
pub unsafe fn test_unchecked(&self, lane: usize) -> bool {
160164
unsafe { self.0.test_unchecked(lane) }
161165
}
@@ -165,6 +169,7 @@ where
165169
/// # Panics
166170
/// Panics if `lane` is greater than or equal to the number of lanes in the vector.
167171
#[inline]
172+
#[must_use = "method returns a new bool and does not mutate the original value"]
168173
pub fn test(&self, lane: usize) -> bool {
169174
assert!(lane < LANES, "lane index out of range");
170175
unsafe { self.test_unchecked(lane) }
@@ -195,24 +200,30 @@ where
195200

196201
/// Convert this mask to a bitmask, with one bit set per lane.
197202
#[cfg(feature = "generic_const_exprs")]
203+
#[inline]
204+
#[must_use = "method returns a new array and does not mutate the original value"]
198205
pub fn to_bitmask(self) -> [u8; LaneCount::<LANES>::BITMASK_LEN] {
199206
self.0.to_bitmask()
200207
}
201208

202209
/// Convert a bitmask to a mask.
203210
#[cfg(feature = "generic_const_exprs")]
211+
#[inline]
212+
#[must_use = "method returns a new mask and does not mutate the original value"]
204213
pub fn from_bitmask(bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN]) -> Self {
205214
Self(mask_impl::Mask::from_bitmask(bitmask))
206215
}
207216

208217
/// Returns true if any lane is set, or false otherwise.
209218
#[inline]
219+
#[must_use = "method returns a new bool and does not mutate the original value"]
210220
pub fn any(self) -> bool {
211221
self.0.any()
212222
}
213223

214224
/// Returns true if all lanes are set, or false otherwise.
215225
#[inline]
226+
#[must_use = "method returns a new bool and does not mutate the original value"]
216227
pub fn all(self) -> bool {
217228
self.0.all()
218229
}
@@ -245,6 +256,7 @@ where
245256
LaneCount<LANES>: SupportedLaneCount,
246257
{
247258
#[inline]
259+
#[must_use = "method returns a defaulted mask with all lanes set to false (0)"]
248260
fn default() -> Self {
249261
Self::splat(false)
250262
}
@@ -256,6 +268,7 @@ where
256268
LaneCount<LANES>: SupportedLaneCount,
257269
{
258270
#[inline]
271+
#[must_use = "method returns a new bool and does not mutate the original value"]
259272
fn eq(&self, other: &Self) -> bool {
260273
self.0 == other.0
261274
}
@@ -267,6 +280,7 @@ where
267280
LaneCount<LANES>: SupportedLaneCount,
268281
{
269282
#[inline]
283+
#[must_use = "method returns a new Ordering and does not mutate the original value"]
270284
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
271285
self.0.partial_cmp(&other.0)
272286
}
@@ -291,6 +305,7 @@ where
291305
{
292306
type Output = Self;
293307
#[inline]
308+
#[must_use = "method returns a new mask and does not mutate the original value"]
294309
fn bitand(self, rhs: Self) -> Self {
295310
Self(self.0 & rhs.0)
296311
}
@@ -303,6 +318,7 @@ where
303318
{
304319
type Output = Self;
305320
#[inline]
321+
#[must_use = "method returns a new mask and does not mutate the original value"]
306322
fn bitand(self, rhs: bool) -> Self {
307323
self & Self::splat(rhs)
308324
}
@@ -315,6 +331,7 @@ where
315331
{
316332
type Output = Mask<T, LANES>;
317333
#[inline]
334+
#[must_use = "method returns a new mask and does not mutate the original value"]
318335
fn bitand(self, rhs: Mask<T, LANES>) -> Mask<T, LANES> {
319336
Mask::splat(self) & rhs
320337
}
@@ -327,6 +344,7 @@ where
327344
{
328345
type Output = Self;
329346
#[inline]
347+
#[must_use = "method returns a new mask and does not mutate the original value"]
330348
fn bitor(self, rhs: Self) -> Self {
331349
Self(self.0 | rhs.0)
332350
}
@@ -339,6 +357,7 @@ where
339357
{
340358
type Output = Self;
341359
#[inline]
360+
#[must_use = "method returns a new mask and does not mutate the original value"]
342361
fn bitor(self, rhs: bool) -> Self {
343362
self | Self::splat(rhs)
344363
}
@@ -351,6 +370,7 @@ where
351370
{
352371
type Output = Mask<T, LANES>;
353372
#[inline]
373+
#[must_use = "method returns a new mask and does not mutate the original value"]
354374
fn bitor(self, rhs: Mask<T, LANES>) -> Mask<T, LANES> {
355375
Mask::splat(self) | rhs
356376
}
@@ -363,6 +383,7 @@ where
363383
{
364384
type Output = Self;
365385
#[inline]
386+
#[must_use = "method returns a new mask and does not mutate the original value"]
366387
fn bitxor(self, rhs: Self) -> Self::Output {
367388
Self(self.0 ^ rhs.0)
368389
}
@@ -375,6 +396,7 @@ where
375396
{
376397
type Output = Self;
377398
#[inline]
399+
#[must_use = "method returns a new mask and does not mutate the original value"]
378400
fn bitxor(self, rhs: bool) -> Self::Output {
379401
self ^ Self::splat(rhs)
380402
}
@@ -387,6 +409,7 @@ where
387409
{
388410
type Output = Mask<T, LANES>;
389411
#[inline]
412+
#[must_use = "method returns a new mask and does not mutate the original value"]
390413
fn bitxor(self, rhs: Mask<T, LANES>) -> Self::Output {
391414
Mask::splat(self) ^ rhs
392415
}
@@ -399,6 +422,7 @@ where
399422
{
400423
type Output = Mask<T, LANES>;
401424
#[inline]
425+
#[must_use = "method returns a new mask and does not mutate the original value"]
402426
fn not(self) -> Self::Output {
403427
Self(!self.0)
404428
}

‎library/portable-simd/crates/core_simd/src/masks/bitmask.rs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(unused_imports)]
12
use super::MaskElement;
23
use crate::simd::intrinsics;
34
use crate::simd::{LaneCount, Simd, SupportedLaneCount};
@@ -73,6 +74,7 @@ where
7374
LaneCount<LANES>: SupportedLaneCount,
7475
{
7576
#[inline]
77+
#[must_use = "method returns a new mask and does not mutate the original value"]
7678
pub fn splat(value: bool) -> Self {
7779
let mut mask = <LaneCount<LANES> as SupportedLaneCount>::BitMask::default();
7880
if value {
@@ -87,6 +89,7 @@ where
8789
}
8890

8991
#[inline]
92+
#[must_use = "method returns a new bool and does not mutate the original value"]
9093
pub unsafe fn test_unchecked(&self, lane: usize) -> bool {
9194
(self.0.as_ref()[lane / 8] >> (lane % 8)) & 0x1 > 0
9295
}
@@ -99,43 +102,41 @@ where
99102
}
100103

101104
#[inline]
105+
#[must_use = "method returns a new vector and does not mutate the original value"]
102106
pub fn to_int(self) -> Simd<T, LANES> {
103107
unsafe {
104-
let mask: <LaneCount<LANES> as SupportedLaneCount>::IntBitMask =
105-
core::mem::transmute_copy(&self);
106-
intrinsics::simd_select_bitmask(mask, Simd::splat(T::TRUE), Simd::splat(T::FALSE))
108+
crate::intrinsics::simd_select_bitmask(
109+
self.0,
110+
Simd::splat(T::TRUE),
111+
Simd::splat(T::FALSE),
112+
)
107113
}
108114
}
109115

110116
#[inline]
117+
#[must_use = "method returns a new mask and does not mutate the original value"]
111118
pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self {
112-
// TODO remove the transmute when rustc is more flexible
113-
assert_eq!(
114-
core::mem::size_of::<<LaneCount::<LANES> as SupportedLaneCount>::BitMask>(),
115-
core::mem::size_of::<<LaneCount::<LANES> as SupportedLaneCount>::IntBitMask>(),
116-
);
117-
unsafe {
118-
let mask: <LaneCount<LANES> as SupportedLaneCount>::IntBitMask =
119-
intrinsics::simd_bitmask(value);
120-
Self(core::mem::transmute_copy(&mask), PhantomData)
121-
}
119+
unsafe { Self(crate::intrinsics::simd_bitmask(value), PhantomData) }
122120
}
123121

124122
#[cfg(feature = "generic_const_exprs")]
125123
#[inline]
124+
#[must_use = "method returns a new array and does not mutate the original value"]
126125
pub fn to_bitmask(self) -> [u8; LaneCount::<LANES>::BITMASK_LEN] {
127126
// Safety: these are the same type and we are laundering the generic
128127
unsafe { core::mem::transmute_copy(&self.0) }
129128
}
130129

131130
#[cfg(feature = "generic_const_exprs")]
132131
#[inline]
132+
#[must_use = "method returns a new mask and does not mutate the original value"]
133133
pub fn from_bitmask(bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN]) -> Self {
134134
// Safety: these are the same type and we are laundering the generic
135135
Self(unsafe { core::mem::transmute_copy(&bitmask) }, PhantomData)
136136
}
137137

138138
#[inline]
139+
#[must_use = "method returns a new mask and does not mutate the original value"]
139140
pub fn convert<U>(self) -> Mask<U, LANES>
140141
where
141142
U: MaskElement,
@@ -144,11 +145,13 @@ where
144145
}
145146

146147
#[inline]
148+
#[must_use = "method returns a new bool and does not mutate the original value"]
147149
pub fn any(self) -> bool {
148150
self != Self::splat(false)
149151
}
150152

151153
#[inline]
154+
#[must_use = "method returns a new bool and does not mutate the original value"]
152155
pub fn all(self) -> bool {
153156
self == Self::splat(true)
154157
}
@@ -162,6 +165,7 @@ where
162165
{
163166
type Output = Self;
164167
#[inline]
168+
#[must_use = "method returns a new mask and does not mutate the original value"]
165169
fn bitand(mut self, rhs: Self) -> Self {
166170
for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) {
167171
*l &= r;
@@ -178,6 +182,7 @@ where
178182
{
179183
type Output = Self;
180184
#[inline]
185+
#[must_use = "method returns a new mask and does not mutate the original value"]
181186
fn bitor(mut self, rhs: Self) -> Self {
182187
for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) {
183188
*l |= r;
@@ -193,6 +198,7 @@ where
193198
{
194199
type Output = Self;
195200
#[inline]
201+
#[must_use = "method returns a new mask and does not mutate the original value"]
196202
fn bitxor(mut self, rhs: Self) -> Self::Output {
197203
for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) {
198204
*l ^= r;
@@ -208,6 +214,7 @@ where
208214
{
209215
type Output = Self;
210216
#[inline]
217+
#[must_use = "method returns a new mask and does not mutate the original value"]
211218
fn not(mut self) -> Self::Output {
212219
for x in self.0.as_mut() {
213220
*x = !*x;

‎library/portable-simd/crates/core_simd/src/masks/full_masks.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ where
2323
LaneCount<LANES>: SupportedLaneCount,
2424
{
2525
#[inline]
26+
#[must_use = "method returns a new mask and does not mutate the original value"]
2627
fn clone(&self) -> Self {
2728
*self
2829
}
@@ -70,11 +71,14 @@ where
7071
T: MaskElement,
7172
LaneCount<LANES>: SupportedLaneCount,
7273
{
74+
#[inline]
75+
#[must_use = "method returns a new mask and does not mutate the original value"]
7376
pub fn splat(value: bool) -> Self {
7477
Self(Simd::splat(if value { T::TRUE } else { T::FALSE }))
7578
}
7679

7780
#[inline]
81+
#[must_use = "method returns a new bool and does not mutate the original value"]
7882
pub unsafe fn test_unchecked(&self, lane: usize) -> bool {
7983
T::eq(self.0[lane], T::TRUE)
8084
}
@@ -85,16 +89,19 @@ where
8589
}
8690

8791
#[inline]
92+
#[must_use = "method returns a new vector and does not mutate the original value"]
8893
pub fn to_int(self) -> Simd<T, LANES> {
8994
self.0
9095
}
9196

9297
#[inline]
98+
#[must_use = "method returns a new mask and does not mutate the original value"]
9399
pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self {
94100
Self(value)
95101
}
96102

97103
#[inline]
104+
#[must_use = "method returns a new mask and does not mutate the original value"]
98105
pub fn convert<U>(self) -> Mask<U, LANES>
99106
where
100107
U: MaskElement,
@@ -104,17 +111,11 @@ where
104111

105112
#[cfg(feature = "generic_const_exprs")]
106113
#[inline]
114+
#[must_use = "method returns a new array and does not mutate the original value"]
107115
pub fn to_bitmask(self) -> [u8; LaneCount::<LANES>::BITMASK_LEN] {
108116
unsafe {
109-
// TODO remove the transmute when rustc can use arrays of u8 as bitmasks
110-
assert_eq!(
111-
core::mem::size_of::<<LaneCount::<LANES> as SupportedLaneCount>::IntBitMask>(),
112-
LaneCount::<LANES>::BITMASK_LEN,
113-
);
114-
let bitmask: <LaneCount<LANES> as SupportedLaneCount>::IntBitMask =
115-
intrinsics::simd_bitmask(self.0);
116117
let mut bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN] =
117-
core::mem::transmute_copy(&bitmask);
118+
crate::intrinsics::simd_bitmask(self.0);
118119

119120
// There is a bug where LLVM appears to implement this operation with the wrong
120121
// bit order.
@@ -131,6 +132,7 @@ where
131132

132133
#[cfg(feature = "generic_const_exprs")]
133134
#[inline]
135+
#[must_use = "method returns a new mask and does not mutate the original value"]
134136
pub fn from_bitmask(mut bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN]) -> Self {
135137
unsafe {
136138
// There is a bug where LLVM appears to implement this operation with the wrong
@@ -142,15 +144,7 @@ where
142144
}
143145
}
144146

145-
// TODO remove the transmute when rustc can use arrays of u8 as bitmasks
146-
assert_eq!(
147-
core::mem::size_of::<<LaneCount::<LANES> as SupportedLaneCount>::IntBitMask>(),
148-
LaneCount::<LANES>::BITMASK_LEN,
149-
);
150-
let bitmask: <LaneCount<LANES> as SupportedLaneCount>::IntBitMask =
151-
core::mem::transmute_copy(&bitmask);
152-
153-
Self::from_int_unchecked(intrinsics::simd_select_bitmask(
147+
Self::from_int_unchecked(crate::intrinsics::simd_select_bitmask(
154148
bitmask,
155149
Self::splat(true).to_int(),
156150
Self::splat(false).to_int(),
@@ -159,11 +153,13 @@ where
159153
}
160154

161155
#[inline]
156+
#[must_use = "method returns a new bool and does not mutate the original value"]
162157
pub fn any(self) -> bool {
163158
unsafe { intrinsics::simd_reduce_any(self.to_int()) }
164159
}
165160

166161
#[inline]
162+
#[must_use = "method returns a new vector and does not mutate the original value"]
167163
pub fn all(self) -> bool {
168164
unsafe { intrinsics::simd_reduce_all(self.to_int()) }
169165
}
@@ -186,6 +182,7 @@ where
186182
{
187183
type Output = Self;
188184
#[inline]
185+
#[must_use = "method returns a new mask and does not mutate the original value"]
189186
fn bitand(self, rhs: Self) -> Self {
190187
unsafe { Self(intrinsics::simd_and(self.0, rhs.0)) }
191188
}
@@ -198,6 +195,7 @@ where
198195
{
199196
type Output = Self;
200197
#[inline]
198+
#[must_use = "method returns a new mask and does not mutate the original value"]
201199
fn bitor(self, rhs: Self) -> Self {
202200
unsafe { Self(intrinsics::simd_or(self.0, rhs.0)) }
203201
}
@@ -210,6 +208,7 @@ where
210208
{
211209
type Output = Self;
212210
#[inline]
211+
#[must_use = "method returns a new mask and does not mutate the original value"]
213212
fn bitxor(self, rhs: Self) -> Self {
214213
unsafe { Self(intrinsics::simd_xor(self.0, rhs.0)) }
215214
}
@@ -222,6 +221,7 @@ where
222221
{
223222
type Output = Self;
224223
#[inline]
224+
#[must_use = "method returns a new mask and does not mutate the original value"]
225225
fn not(self) -> Self::Output {
226226
Self::splat(true) ^ self
227227
}

‎library/portable-simd/crates/core_simd/src/math.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ macro_rules! impl_uint_arith {
1717
/// let max = Simd::splat(MAX);
1818
/// let unsat = x + max;
1919
/// let sat = x.saturating_add(max);
20-
/// assert_eq!(x - 1, unsat);
20+
/// assert_eq!(unsat, Simd::from_array([1, 0, MAX, MAX - 1]));
2121
/// assert_eq!(sat, max);
2222
/// ```
2323
#[inline]
@@ -37,7 +37,7 @@ macro_rules! impl_uint_arith {
3737
/// let max = Simd::splat(MAX);
3838
/// let unsat = x - max;
3939
/// let sat = x.saturating_sub(max);
40-
/// assert_eq!(unsat, x + 1);
40+
/// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0]));
4141
/// assert_eq!(sat, Simd::splat(0));
4242
#[inline]
4343
pub fn saturating_sub(self, second: Self) -> Self {
@@ -105,7 +105,7 @@ macro_rules! impl_int_arith {
105105
#[inline]
106106
pub fn abs(self) -> Self {
107107
const SHR: $ty = <$ty>::BITS as $ty - 1;
108-
let m = self >> SHR;
108+
let m = self >> Simd::splat(SHR);
109109
(self^m) - m
110110
}
111111

@@ -128,7 +128,7 @@ macro_rules! impl_int_arith {
128128
pub fn saturating_abs(self) -> Self {
129129
// arith shift for -1 or 0 mask based on sign bit, giving 2s complement
130130
const SHR: $ty = <$ty>::BITS as $ty - 1;
131-
let m = self >> SHR;
131+
let m = self >> Simd::splat(SHR);
132132
(self^m).saturating_sub(m)
133133
}
134134

‎library/portable-simd/crates/core_simd/src/ops.rs

Lines changed: 19 additions & 400 deletions
Large diffs are not rendered by default.
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//! Assignment operators
2+
use super::*;
3+
use core::ops::{AddAssign, MulAssign}; // commutative binary op-assignment
4+
use core::ops::{BitAndAssign, BitOrAssign, BitXorAssign}; // commutative bit binary op-assignment
5+
use core::ops::{DivAssign, RemAssign, SubAssign}; // non-commutative binary op-assignment
6+
use core::ops::{ShlAssign, ShrAssign}; // non-commutative bit binary op-assignment
7+
8+
// Arithmetic
9+
10+
macro_rules! assign_ops {
11+
($(impl<T, U, const LANES: usize> $assignTrait:ident<U> for Simd<T, LANES>
12+
where
13+
Self: $trait:ident,
14+
{
15+
fn $assign_call:ident(rhs: U) {
16+
$call:ident
17+
}
18+
})*) => {
19+
$(impl<T, U, const LANES: usize> $assignTrait<U> for Simd<T, LANES>
20+
where
21+
Self: $trait<U, Output = Self>,
22+
T: SimdElement,
23+
LaneCount<LANES>: SupportedLaneCount,
24+
{
25+
#[inline]
26+
fn $assign_call(&mut self, rhs: U) {
27+
*self = self.$call(rhs);
28+
}
29+
})*
30+
}
31+
}
32+
33+
assign_ops! {
34+
// Arithmetic
35+
impl<T, U, const LANES: usize> AddAssign<U> for Simd<T, LANES>
36+
where
37+
Self: Add,
38+
{
39+
fn add_assign(rhs: U) {
40+
add
41+
}
42+
}
43+
44+
impl<T, U, const LANES: usize> MulAssign<U> for Simd<T, LANES>
45+
where
46+
Self: Mul,
47+
{
48+
fn mul_assign(rhs: U) {
49+
mul
50+
}
51+
}
52+
53+
impl<T, U, const LANES: usize> SubAssign<U> for Simd<T, LANES>
54+
where
55+
Self: Sub,
56+
{
57+
fn sub_assign(rhs: U) {
58+
sub
59+
}
60+
}
61+
62+
impl<T, U, const LANES: usize> DivAssign<U> for Simd<T, LANES>
63+
where
64+
Self: Div,
65+
{
66+
fn div_assign(rhs: U) {
67+
div
68+
}
69+
}
70+
impl<T, U, const LANES: usize> RemAssign<U> for Simd<T, LANES>
71+
where
72+
Self: Rem,
73+
{
74+
fn rem_assign(rhs: U) {
75+
rem
76+
}
77+
}
78+
79+
// Bitops
80+
impl<T, U, const LANES: usize> BitAndAssign<U> for Simd<T, LANES>
81+
where
82+
Self: BitAnd,
83+
{
84+
fn bitand_assign(rhs: U) {
85+
bitand
86+
}
87+
}
88+
89+
impl<T, U, const LANES: usize> BitOrAssign<U> for Simd<T, LANES>
90+
where
91+
Self: BitOr,
92+
{
93+
fn bitor_assign(rhs: U) {
94+
bitor
95+
}
96+
}
97+
98+
impl<T, U, const LANES: usize> BitXorAssign<U> for Simd<T, LANES>
99+
where
100+
Self: BitXor,
101+
{
102+
fn bitxor_assign(rhs: U) {
103+
bitxor
104+
}
105+
}
106+
107+
impl<T, U, const LANES: usize> ShlAssign<U> for Simd<T, LANES>
108+
where
109+
Self: Shl,
110+
{
111+
fn shl_assign(rhs: U) {
112+
shl
113+
}
114+
}
115+
116+
impl<T, U, const LANES: usize> ShrAssign<U> for Simd<T, LANES>
117+
where
118+
Self: Shr,
119+
{
120+
fn shr_assign(rhs: U) {
121+
shr
122+
}
123+
}
124+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//! This module hacks in "implicit deref" for Simd's operators.
2+
//! Ideally, Rust would take care of this itself,
3+
//! and method calls usually handle the LHS implicitly.
4+
//! But this is not the case with arithmetic ops.
5+
use super::*;
6+
7+
macro_rules! deref_lhs {
8+
(impl<T, const LANES: usize> $trait:ident for $simd:ty {
9+
fn $call:ident
10+
}) => {
11+
impl<T, const LANES: usize> $trait<$simd> for &$simd
12+
where
13+
T: SimdElement,
14+
$simd: $trait<$simd, Output = $simd>,
15+
LaneCount<LANES>: SupportedLaneCount,
16+
{
17+
type Output = Simd<T, LANES>;
18+
19+
#[inline]
20+
#[must_use = "operator returns a new vector without mutating the inputs"]
21+
fn $call(self, rhs: $simd) -> Self::Output {
22+
(*self).$call(rhs)
23+
}
24+
}
25+
};
26+
}
27+
28+
macro_rules! deref_rhs {
29+
(impl<T, const LANES: usize> $trait:ident for $simd:ty {
30+
fn $call:ident
31+
}) => {
32+
impl<T, const LANES: usize> $trait<&$simd> for $simd
33+
where
34+
T: SimdElement,
35+
$simd: $trait<$simd, Output = $simd>,
36+
LaneCount<LANES>: SupportedLaneCount,
37+
{
38+
type Output = Simd<T, LANES>;
39+
40+
#[inline]
41+
#[must_use = "operator returns a new vector without mutating the inputs"]
42+
fn $call(self, rhs: &$simd) -> Self::Output {
43+
self.$call(*rhs)
44+
}
45+
}
46+
};
47+
}
48+
49+
macro_rules! deref_ops {
50+
($(impl<T, const LANES: usize> $trait:ident for $simd:ty {
51+
fn $call:ident
52+
})*) => {
53+
$(
54+
deref_rhs! {
55+
impl<T, const LANES: usize> $trait for $simd {
56+
fn $call
57+
}
58+
}
59+
deref_lhs! {
60+
impl<T, const LANES: usize> $trait for $simd {
61+
fn $call
62+
}
63+
}
64+
impl<'lhs, 'rhs, T, const LANES: usize> $trait<&'rhs $simd> for &'lhs $simd
65+
where
66+
T: SimdElement,
67+
$simd: $trait<$simd, Output = $simd>,
68+
LaneCount<LANES>: SupportedLaneCount,
69+
{
70+
type Output = $simd;
71+
72+
#[inline]
73+
#[must_use = "operator returns a new vector without mutating the inputs"]
74+
fn $call(self, rhs: &$simd) -> Self::Output {
75+
(*self).$call(*rhs)
76+
}
77+
}
78+
)*
79+
}
80+
}
81+
82+
deref_ops! {
83+
// Arithmetic
84+
impl<T, const LANES: usize> Add for Simd<T, LANES> {
85+
fn add
86+
}
87+
88+
impl<T, const LANES: usize> Mul for Simd<T, LANES> {
89+
fn mul
90+
}
91+
92+
impl<T, const LANES: usize> Sub for Simd<T, LANES> {
93+
fn sub
94+
}
95+
96+
impl<T, const LANES: usize> Div for Simd<T, LANES> {
97+
fn div
98+
}
99+
100+
impl<T, const LANES: usize> Rem for Simd<T, LANES> {
101+
fn rem
102+
}
103+
104+
// Bitops
105+
impl<T, const LANES: usize> BitAnd for Simd<T, LANES> {
106+
fn bitand
107+
}
108+
109+
impl<T, const LANES: usize> BitOr for Simd<T, LANES> {
110+
fn bitor
111+
}
112+
113+
impl<T, const LANES: usize> BitXor for Simd<T, LANES> {
114+
fn bitxor
115+
}
116+
117+
impl<T, const LANES: usize> Shl for Simd<T, LANES> {
118+
fn shl
119+
}
120+
121+
impl<T, const LANES: usize> Shr for Simd<T, LANES> {
122+
fn shr
123+
}
124+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use crate::simd::intrinsics;
2+
use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
3+
use core::ops::{Neg, Not}; // unary ops
4+
5+
macro_rules! neg {
6+
($(impl<const LANES: usize> Neg for Simd<$scalar:ty, LANES>)*) => {
7+
$(impl<const LANES: usize> Neg for Simd<$scalar, LANES>
8+
where
9+
$scalar: SimdElement,
10+
LaneCount<LANES>: SupportedLaneCount,
11+
{
12+
type Output = Self;
13+
14+
#[inline]
15+
#[must_use = "operator returns a new vector without mutating the input"]
16+
fn neg(self) -> Self::Output {
17+
unsafe { intrinsics::simd_neg(self) }
18+
}
19+
})*
20+
}
21+
}
22+
23+
neg! {
24+
impl<const LANES: usize> Neg for Simd<f32, LANES>
25+
26+
impl<const LANES: usize> Neg for Simd<f64, LANES>
27+
28+
impl<const LANES: usize> Neg for Simd<i8, LANES>
29+
30+
impl<const LANES: usize> Neg for Simd<i16, LANES>
31+
32+
impl<const LANES: usize> Neg for Simd<i32, LANES>
33+
34+
impl<const LANES: usize> Neg for Simd<i64, LANES>
35+
36+
impl<const LANES: usize> Neg for Simd<isize, LANES>
37+
}
38+
39+
macro_rules! not {
40+
($(impl<const LANES: usize> Not for Simd<$scalar:ty, LANES>)*) => {
41+
$(impl<const LANES: usize> Not for Simd<$scalar, LANES>
42+
where
43+
$scalar: SimdElement,
44+
LaneCount<LANES>: SupportedLaneCount,
45+
{
46+
type Output = Self;
47+
48+
#[inline]
49+
#[must_use = "operator returns a new vector without mutating the input"]
50+
fn not(self) -> Self::Output {
51+
self ^ (Simd::splat(!(0 as $scalar)))
52+
}
53+
})*
54+
}
55+
}
56+
57+
not! {
58+
impl<const LANES: usize> Not for Simd<i8, LANES>
59+
60+
impl<const LANES: usize> Not for Simd<i16, LANES>
61+
62+
impl<const LANES: usize> Not for Simd<i32, LANES>
63+
64+
impl<const LANES: usize> Not for Simd<i64, LANES>
65+
66+
impl<const LANES: usize> Not for Simd<isize, LANES>
67+
68+
impl<const LANES: usize> Not for Simd<u8, LANES>
69+
70+
impl<const LANES: usize> Not for Simd<u16, LANES>
71+
72+
impl<const LANES: usize> Not for Simd<u32, LANES>
73+
74+
impl<const LANES: usize> Not for Simd<u64, LANES>
75+
76+
impl<const LANES: usize> Not for Simd<usize, LANES>
77+
}

‎library/portable-simd/crates/core_simd/src/reduction.rs

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use crate::simd::intrinsics::{
22
simd_reduce_add_ordered, simd_reduce_and, simd_reduce_max, simd_reduce_min,
33
simd_reduce_mul_ordered, simd_reduce_or, simd_reduce_xor,
44
};
5-
use crate::simd::{LaneCount, Simd, SupportedLaneCount};
5+
use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
6+
use core::ops::{BitAnd, BitOr, BitXor};
67

78
macro_rules! impl_integer_reductions {
89
{ $scalar:ty } => {
@@ -22,27 +23,6 @@ macro_rules! impl_integer_reductions {
2223
unsafe { simd_reduce_mul_ordered(self, 1) }
2324
}
2425

25-
/// Horizontal bitwise "and". Returns the cumulative bitwise "and" across the lanes of
26-
/// the vector.
27-
#[inline]
28-
pub fn horizontal_and(self) -> $scalar {
29-
unsafe { simd_reduce_and(self) }
30-
}
31-
32-
/// Horizontal bitwise "or". Returns the cumulative bitwise "or" across the lanes of
33-
/// the vector.
34-
#[inline]
35-
pub fn horizontal_or(self) -> $scalar {
36-
unsafe { simd_reduce_or(self) }
37-
}
38-
39-
/// Horizontal bitwise "xor". Returns the cumulative bitwise "xor" across the lanes of
40-
/// the vector.
41-
#[inline]
42-
pub fn horizontal_xor(self) -> $scalar {
43-
unsafe { simd_reduce_xor(self) }
44-
}
45-
4626
/// Horizontal maximum. Returns the maximum lane in the vector.
4727
#[inline]
4828
pub fn horizontal_max(self) -> $scalar {
@@ -121,3 +101,45 @@ macro_rules! impl_float_reductions {
121101

122102
impl_float_reductions! { f32 }
123103
impl_float_reductions! { f64 }
104+
105+
impl<T, const LANES: usize> Simd<T, LANES>
106+
where
107+
Self: BitAnd<Self, Output = Self>,
108+
T: SimdElement + BitAnd<T, Output = T>,
109+
LaneCount<LANES>: SupportedLaneCount,
110+
{
111+
/// Horizontal bitwise "and". Returns the cumulative bitwise "and" across the lanes of
112+
/// the vector.
113+
#[inline]
114+
pub fn horizontal_and(self) -> T {
115+
unsafe { simd_reduce_and(self) }
116+
}
117+
}
118+
119+
impl<T, const LANES: usize> Simd<T, LANES>
120+
where
121+
Self: BitOr<Self, Output = Self>,
122+
T: SimdElement + BitOr<T, Output = T>,
123+
LaneCount<LANES>: SupportedLaneCount,
124+
{
125+
/// Horizontal bitwise "or". Returns the cumulative bitwise "or" across the lanes of
126+
/// the vector.
127+
#[inline]
128+
pub fn horizontal_or(self) -> T {
129+
unsafe { simd_reduce_or(self) }
130+
}
131+
}
132+
133+
impl<T, const LANES: usize> Simd<T, LANES>
134+
where
135+
Self: BitXor<Self, Output = Self>,
136+
T: SimdElement + BitXor<T, Output = T>,
137+
LaneCount<LANES>: SupportedLaneCount,
138+
{
139+
/// Horizontal bitwise "xor". Returns the cumulative bitwise "xor" across the lanes of
140+
/// the vector.
141+
#[inline]
142+
pub fn horizontal_xor(self) -> T {
143+
unsafe { simd_reduce_xor(self) }
144+
}
145+
}

‎library/portable-simd/crates/core_simd/src/select.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ where
1717
LaneCount<LANES>: SupportedLaneCount,
1818
{
1919
#[inline]
20+
#[must_use = "method returns a new vector and does not mutate the original inputs"]
2021
fn select(mask: Mask<T::Mask, LANES>, true_values: Self, false_values: Self) -> Self {
2122
unsafe { intrinsics::simd_select(mask.to_int(), true_values, false_values) }
2223
}
@@ -35,6 +36,7 @@ where
3536
LaneCount<LANES>: SupportedLaneCount,
3637
{
3738
#[inline]
39+
#[must_use = "method returns a new vector and does not mutate the original inputs"]
3840
fn select(mask: Self, true_values: Self, false_values: Self) -> Self {
3941
mask & true_values | !mask & false_values
4042
}
@@ -80,6 +82,7 @@ where
8082
/// assert_eq!(c.to_array(), [true, false, true, false]);
8183
/// ```
8284
#[inline]
85+
#[must_use = "method returns a new vector and does not mutate the original inputs"]
8386
pub fn select<S: Select<Self>>(self, true_values: S, false_values: S) -> S {
8487
S::select(self, true_values, false_values)
8588
}

‎library/portable-simd/crates/core_simd/src/swizzle.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ pub trait Swizzle<const INPUT_LANES: usize, const OUTPUT_LANES: usize> {
8787
/// Create a new vector from the lanes of `vector`.
8888
///
8989
/// Lane `i` of the output is `vector[Self::INDEX[i]]`.
90+
#[inline]
91+
#[must_use = "method returns a new vector and does not mutate the original inputs"]
9092
fn swizzle<T>(vector: Simd<T, INPUT_LANES>) -> Simd<T, OUTPUT_LANES>
9193
where
9294
T: SimdElement,
@@ -106,6 +108,8 @@ pub trait Swizzle2<const INPUT_LANES: usize, const OUTPUT_LANES: usize> {
106108
///
107109
/// Lane `i` is `first[j]` when `Self::INDEX[i]` is `First(j)`, or `second[j]` when it is
108110
/// `Second(j)`.
111+
#[inline]
112+
#[must_use = "method returns a new vector and does not mutate the original inputs"]
109113
fn swizzle2<T>(
110114
first: Simd<T, INPUT_LANES>,
111115
second: Simd<T, INPUT_LANES>,
@@ -182,6 +186,7 @@ where
182186
{
183187
/// Reverse the order of the lanes in the vector.
184188
#[inline]
189+
#[must_use = "method returns a new vector and does not mutate the original inputs"]
185190
pub fn reverse(self) -> Self {
186191
const fn reverse_index<const LANES: usize>() -> [usize; LANES] {
187192
let mut index = [0; LANES];
@@ -206,6 +211,7 @@ where
206211
/// while the last `LANES - OFFSET` elements move to the front. After calling `rotate_lanes_left`,
207212
/// the element previously in lane `OFFSET` will become the first element in the slice.
208213
#[inline]
214+
#[must_use = "method returns a new vector and does not mutate the original inputs"]
209215
pub fn rotate_lanes_left<const OFFSET: usize>(self) -> Self {
210216
const fn rotate_index<const OFFSET: usize, const LANES: usize>() -> [usize; LANES] {
211217
let offset = OFFSET % LANES;
@@ -231,6 +237,7 @@ where
231237
/// the end while the last `OFFSET` elements move to the front. After calling `rotate_lanes_right`,
232238
/// the element previously at index `LANES - OFFSET` will become the first element in the slice.
233239
#[inline]
240+
#[must_use = "method returns a new vector and does not mutate the original inputs"]
234241
pub fn rotate_lanes_right<const OFFSET: usize>(self) -> Self {
235242
const fn rotate_index<const OFFSET: usize, const LANES: usize>() -> [usize; LANES] {
236243
let offset = LANES - OFFSET % LANES;
@@ -273,6 +280,7 @@ where
273280
/// assert_eq!(y.to_array(), [2, 6, 3, 7]);
274281
/// ```
275282
#[inline]
283+
#[must_use = "method returns a new vector and does not mutate the original inputs"]
276284
pub fn interleave(self, other: Self) -> (Self, Self) {
277285
const fn lo<const LANES: usize>() -> [Which; LANES] {
278286
let mut idx = [Which::First(0); LANES];
@@ -336,6 +344,7 @@ where
336344
/// assert_eq!(y.to_array(), [4, 5, 6, 7]);
337345
/// ```
338346
#[inline]
347+
#[must_use = "method returns a new vector and does not mutate the original inputs"]
339348
pub fn deinterleave(self, other: Self) -> (Self, Self) {
340349
const fn even<const LANES: usize>() -> [Which; LANES] {
341350
let mut idx = [Which::First(0); LANES];

‎library/portable-simd/crates/core_simd/src/vector/float.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ macro_rules! impl_float_vector {
1515
/// Raw transmutation to an unsigned integer vector type with the
1616
/// same size and number of lanes.
1717
#[inline]
18+
#[must_use = "method returns a new vector and does not mutate the original value"]
1819
pub fn to_bits(self) -> Simd<$bits_ty, LANES> {
1920
assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Simd<$bits_ty, LANES>>());
2021
unsafe { core::mem::transmute_copy(&self) }
@@ -23,6 +24,7 @@ macro_rules! impl_float_vector {
2324
/// Raw transmutation from an unsigned integer vector type with the
2425
/// same size and number of lanes.
2526
#[inline]
27+
#[must_use = "method returns a new vector and does not mutate the original value"]
2628
pub fn from_bits(bits: Simd<$bits_ty, LANES>) -> Self {
2729
assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Simd<$bits_ty, LANES>>());
2830
unsafe { core::mem::transmute_copy(&bits) }
@@ -31,6 +33,7 @@ macro_rules! impl_float_vector {
3133
/// Produces a vector where every lane has the absolute value of the
3234
/// equivalently-indexed lane in `self`.
3335
#[inline]
36+
#[must_use = "method returns a new vector and does not mutate the original value"]
3437
pub fn abs(self) -> Self {
3538
unsafe { intrinsics::simd_fabs(self) }
3639
}
@@ -44,79 +47,91 @@ macro_rules! impl_float_vector {
4447
/// hardware in mind.
4548
#[cfg(feature = "std")]
4649
#[inline]
50+
#[must_use = "method returns a new vector and does not mutate the original value"]
4751
pub fn mul_add(self, a: Self, b: Self) -> Self {
4852
unsafe { intrinsics::simd_fma(self, a, b) }
4953
}
5054

5155
/// Produces a vector where every lane has the square root value
5256
/// of the equivalently-indexed lane in `self`
5357
#[inline]
58+
#[must_use = "method returns a new vector and does not mutate the original value"]
5459
#[cfg(feature = "std")]
5560
pub fn sqrt(self) -> Self {
5661
unsafe { intrinsics::simd_fsqrt(self) }
5762
}
5863

5964
/// Takes the reciprocal (inverse) of each lane, `1/x`.
6065
#[inline]
66+
#[must_use = "method returns a new vector and does not mutate the original value"]
6167
pub fn recip(self) -> Self {
6268
Self::splat(1.0) / self
6369
}
6470

6571
/// Converts each lane from radians to degrees.
6672
#[inline]
73+
#[must_use = "method returns a new vector and does not mutate the original value"]
6774
pub fn to_degrees(self) -> Self {
6875
// to_degrees uses a special constant for better precision, so extract that constant
6976
self * Self::splat(<$type>::to_degrees(1.))
7077
}
7178

7279
/// Converts each lane from degrees to radians.
7380
#[inline]
81+
#[must_use = "method returns a new vector and does not mutate the original value"]
7482
pub fn to_radians(self) -> Self {
7583
self * Self::splat(<$type>::to_radians(1.))
7684
}
7785

7886
/// Returns true for each lane if it has a positive sign, including
7987
/// `+0.0`, `NaN`s with positive sign bit and positive infinity.
8088
#[inline]
89+
#[must_use = "method returns a new mask and does not mutate the original value"]
8190
pub fn is_sign_positive(self) -> Mask<$mask_ty, LANES> {
8291
!self.is_sign_negative()
8392
}
8493

8594
/// Returns true for each lane if it has a negative sign, including
8695
/// `-0.0`, `NaN`s with negative sign bit and negative infinity.
8796
#[inline]
97+
#[must_use = "method returns a new mask and does not mutate the original value"]
8898
pub fn is_sign_negative(self) -> Mask<$mask_ty, LANES> {
8999
let sign_bits = self.to_bits() & Simd::splat((!0 >> 1) + 1);
90100
sign_bits.lanes_gt(Simd::splat(0))
91101
}
92102

93103
/// Returns true for each lane if its value is `NaN`.
94104
#[inline]
105+
#[must_use = "method returns a new mask and does not mutate the original value"]
95106
pub fn is_nan(self) -> Mask<$mask_ty, LANES> {
96107
self.lanes_ne(self)
97108
}
98109

99110
/// Returns true for each lane if its value is positive infinity or negative infinity.
100111
#[inline]
112+
#[must_use = "method returns a new mask and does not mutate the original value"]
101113
pub fn is_infinite(self) -> Mask<$mask_ty, LANES> {
102114
self.abs().lanes_eq(Self::splat(<$type>::INFINITY))
103115
}
104116

105117
/// Returns true for each lane if its value is neither infinite nor `NaN`.
106118
#[inline]
119+
#[must_use = "method returns a new mask and does not mutate the original value"]
107120
pub fn is_finite(self) -> Mask<$mask_ty, LANES> {
108121
self.abs().lanes_lt(Self::splat(<$type>::INFINITY))
109122
}
110123

111124
/// Returns true for each lane if its value is subnormal.
112125
#[inline]
126+
#[must_use = "method returns a new mask and does not mutate the original value"]
113127
pub fn is_subnormal(self) -> Mask<$mask_ty, LANES> {
114128
self.abs().lanes_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(<$type>::INFINITY).to_bits()).lanes_eq(Simd::splat(0))
115129
}
116130

117131
/// Returns true for each lane if its value is neither neither zero, infinite,
118132
/// subnormal, or `NaN`.
119133
#[inline]
134+
#[must_use = "method returns a new mask and does not mutate the original value"]
120135
pub fn is_normal(self) -> Mask<$mask_ty, LANES> {
121136
!(self.abs().lanes_eq(Self::splat(0.0)) | self.is_nan() | self.is_subnormal() | self.is_infinite())
122137
}
@@ -127,6 +142,7 @@ macro_rules! impl_float_vector {
127142
/// * `-1.0` if the number is negative, `-0.0`, or `NEG_INFINITY`
128143
/// * `NAN` if the number is `NAN`
129144
#[inline]
145+
#[must_use = "method returns a new vector and does not mutate the original value"]
130146
pub fn signum(self) -> Self {
131147
self.is_nan().select(Self::splat(<$type>::NAN), Self::splat(1.0).copysign(self))
132148
}
@@ -135,6 +151,7 @@ macro_rules! impl_float_vector {
135151
///
136152
/// If any lane is a `NAN`, then a `NAN` with the sign of `sign` is returned.
137153
#[inline]
154+
#[must_use = "method returns a new vector and does not mutate the original value"]
138155
pub fn copysign(self, sign: Self) -> Self {
139156
let sign_bit = sign.to_bits() & Self::splat(-0.).to_bits();
140157
let magnitude = self.to_bits() & !Self::splat(-0.).to_bits();
@@ -145,6 +162,7 @@ macro_rules! impl_float_vector {
145162
///
146163
/// If one of the values is `NAN`, then the other value is returned.
147164
#[inline]
165+
#[must_use = "method returns a new vector and does not mutate the original value"]
148166
pub fn min(self, other: Self) -> Self {
149167
// TODO consider using an intrinsic
150168
self.is_nan().select(
@@ -157,6 +175,7 @@ macro_rules! impl_float_vector {
157175
///
158176
/// If one of the values is `NAN`, then the other value is returned.
159177
#[inline]
178+
#[must_use = "method returns a new vector and does not mutate the original value"]
160179
pub fn max(self, other: Self) -> Self {
161180
// TODO consider using an intrinsic
162181
self.is_nan().select(
@@ -171,6 +190,7 @@ macro_rules! impl_float_vector {
171190
/// greater than `max`, and the corresponding lane in `min` if the lane is less
172191
/// than `min`. Otherwise returns the lane in `self`.
173192
#[inline]
193+
#[must_use = "method returns a new vector and does not mutate the original value"]
174194
pub fn clamp(self, min: Self, max: Self) -> Self {
175195
assert!(
176196
min.lanes_le(max).all(),

‎library/portable-simd/crates/core_simd/src/vector/ptr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ where
2323
pub fn wrapping_add(self, addend: Simd<usize, LANES>) -> Self {
2424
unsafe {
2525
let x: Simd<usize, LANES> = mem::transmute_copy(&self);
26-
mem::transmute_copy(&{ x + (addend * mem::size_of::<T>()) })
26+
mem::transmute_copy(&{ x + (addend * Simd::splat(mem::size_of::<T>())) })
2727
}
2828
}
2929
}
@@ -49,7 +49,7 @@ where
4949
pub fn wrapping_add(self, addend: Simd<usize, LANES>) -> Self {
5050
unsafe {
5151
let x: Simd<usize, LANES> = mem::transmute_copy(&self);
52-
mem::transmute_copy(&{ x + (addend * mem::size_of::<T>()) })
52+
mem::transmute_copy(&{ x + (addend * Simd::splat(mem::size_of::<T>())) })
5353
}
5454
}
5555
}

‎library/portable-simd/crates/core_simd/src/vendor/x86.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ use core::arch::x86_64::*;
88

99
from_transmute! { unsafe u8x16 => __m128i }
1010
from_transmute! { unsafe u8x32 => __m256i }
11-
//from_transmute! { unsafe u8x64 => __m512i }
11+
from_transmute! { unsafe u8x64 => __m512i }
1212
from_transmute! { unsafe i8x16 => __m128i }
1313
from_transmute! { unsafe i8x32 => __m256i }
14-
//from_transmute! { unsafe i8x64 => __m512i }
14+
from_transmute! { unsafe i8x64 => __m512i }
1515

1616
from_transmute! { unsafe u16x8 => __m128i }
1717
from_transmute! { unsafe u16x16 => __m256i }
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Test that we handle all our "auto-deref" cases correctly.
2+
#![feature(portable_simd)]
3+
use core_simd::f32x4;
4+
5+
#[cfg(target_arch = "wasm32")]
6+
use wasm_bindgen_test::*;
7+
8+
#[cfg(target_arch = "wasm32")]
9+
wasm_bindgen_test_configure!(run_in_browser);
10+
11+
#[test]
12+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
13+
fn deref() {
14+
let x = f32x4::splat(1.0);
15+
let y = f32x4::splat(2.0);
16+
let a = &x;
17+
let b = &y;
18+
assert_eq!(f32x4::splat(3.0), x + y);
19+
assert_eq!(f32x4::splat(3.0), x + b);
20+
assert_eq!(f32x4::splat(3.0), a + y);
21+
assert_eq!(f32x4::splat(3.0), a + b);
22+
}

‎library/portable-simd/crates/core_simd/tests/ops_macros.rs

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -38,37 +38,13 @@ macro_rules! impl_binary_op_test {
3838
);
3939
}
4040

41-
fn scalar_rhs<const LANES: usize>() {
42-
test_helpers::test_binary_scalar_rhs_elementwise(
43-
&<Simd<$scalar, LANES> as core::ops::$trait<$scalar>>::$fn,
44-
&$scalar_fn,
45-
&|_, _| true,
46-
);
47-
}
48-
49-
fn scalar_lhs<const LANES: usize>() {
50-
test_helpers::test_binary_scalar_lhs_elementwise(
51-
&<$scalar as core::ops::$trait<Simd<$scalar, LANES>>>::$fn,
52-
&$scalar_fn,
53-
&|_, _| true,
54-
);
55-
}
56-
5741
fn assign<const LANES: usize>() {
5842
test_helpers::test_binary_elementwise(
5943
&|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign>::$fn_assign(&mut a, b); a },
6044
&$scalar_fn,
6145
&|_, _| true,
6246
);
6347
}
64-
65-
fn assign_scalar_rhs<const LANES: usize>() {
66-
test_helpers::test_binary_scalar_rhs_elementwise(
67-
&|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign<$scalar>>::$fn_assign(&mut a, b); a },
68-
&$scalar_fn,
69-
&|_, _| true,
70-
);
71-
}
7248
}
7349
}
7450
};
@@ -99,37 +75,13 @@ macro_rules! impl_binary_checked_op_test {
9975
);
10076
}
10177

102-
fn scalar_rhs<const LANES: usize>() {
103-
test_helpers::test_binary_scalar_rhs_elementwise(
104-
&<Simd<$scalar, LANES> as core::ops::$trait<$scalar>>::$fn,
105-
&$scalar_fn,
106-
&|x, y| x.iter().all(|x| $check_fn(*x, y)),
107-
);
108-
}
109-
110-
fn scalar_lhs<const LANES: usize>() {
111-
test_helpers::test_binary_scalar_lhs_elementwise(
112-
&<$scalar as core::ops::$trait<Simd<$scalar, LANES>>>::$fn,
113-
&$scalar_fn,
114-
&|x, y| y.iter().all(|y| $check_fn(x, *y)),
115-
);
116-
}
117-
11878
fn assign<const LANES: usize>() {
11979
test_helpers::test_binary_elementwise(
12080
&|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign>::$fn_assign(&mut a, b); a },
12181
&$scalar_fn,
12282
&|x, y| x.iter().zip(y.iter()).all(|(x, y)| $check_fn(*x, *y)),
12383
)
12484
}
125-
126-
fn assign_scalar_rhs<const LANES: usize>() {
127-
test_helpers::test_binary_scalar_rhs_elementwise(
128-
&|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign<$scalar>>::$fn_assign(&mut a, b); a },
129-
&$scalar_fn,
130-
&|x, y| x.iter().all(|x| $check_fn(*x, y)),
131-
)
132-
}
13385
}
13486
}
13587
};

‎library/portable-simd/crates/test_helpers/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,12 @@ macro_rules! test_lanes {
376376
fn lanes_32() {
377377
implementation::<32>();
378378
}
379+
380+
#[test]
381+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
382+
fn lanes_64() {
383+
implementation::<64>();
384+
}
379385
}
380386
)*
381387
}
@@ -431,6 +437,12 @@ macro_rules! test_lanes_panic {
431437
fn lanes_32() {
432438
implementation::<32>();
433439
}
440+
441+
#[test]
442+
#[should_panic]
443+
fn lanes_64() {
444+
implementation::<64>();
445+
}
434446
}
435447
)*
436448
}

0 commit comments

Comments
 (0)
Please sign in to comment.