Skip to content

Commit 796bf14

Browse files
committed
Auto merge of #93146 - workingjubilee:use-std-simd, r=Mark-Simulacrum
pub use std::simd::StdFloat; Syncs portable-simd up to commit rust-lang/portable-simd@03f6fbb, Diff: rust-lang/portable-simd@533f0fc...03f6fbb This sync requires a little bit more legwork because it also introduces a trait into `std::simd`, so that it is no longer simply a reexport of `core::simd`. Out of simple-minded consistency and to allow more options, I replicated the pattern for the way `core::simd` is integrated in the first place, however this is not necessary if it doesn't acquire any interdependencies inside `std`: it could be a simple crate reexport. I just don't know yet if that will happen or not. To summarize other misc changes: - Shifts no longer panic, now wrap on too-large shifts (like `Simd` integers usually do!) - mask16x32 will now be many i16s, not many i32s... 🙃 - `#[must_use]` is spread around generously - Adjusts division, float min/max, and `Mask::{from,to}_array` internally to be faster - Adds the much-requested `Simd::cast::<U>` function (equivalent to `simd.to_array().map(|lane| lane as U)`)
2 parents 1be5c8f + e96159e commit 796bf14

File tree

18 files changed

+537
-335
lines changed

18 files changed

+537
-335
lines changed

library/portable-simd/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22

33
members = [
44
"crates/core_simd",
5+
"crates/std_float",
56
"crates/test_helpers",
67
]

library/portable-simd/crates/core_simd/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@ features = ["alloc"]
2626

2727
[dev-dependencies.test_helpers]
2828
path = "../test_helpers"
29+
30+
[dev-dependencies]
31+
std_float = { path = "../std_float/", features = ["as_crate"] }

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

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
#![cfg_attr(feature = "std", feature(portable_simd))]
1+
#![feature(portable_simd)]
2+
extern crate std_float;
23

34
/// Benchmarks game nbody code
45
/// Taken from the `packed_simd` crate
56
/// Run this benchmark with `cargo test --example nbody`
6-
#[cfg(feature = "std")]
77
mod nbody {
8-
use core_simd::*;
8+
use core_simd::simd::*;
9+
#[allow(unused)] // False positive?
10+
use std_float::StdFloat;
911

1012
use std::f64::consts::PI;
1113
const SOLAR_MASS: f64 = 4.0 * PI * PI;
@@ -167,7 +169,6 @@ mod nbody {
167169
}
168170
}
169171

170-
#[cfg(feature = "std")]
171172
#[cfg(test)]
172173
mod tests {
173174
// Good enough for demonstration purposes, not going for strictness here.
@@ -184,7 +185,6 @@ mod tests {
184185
}
185186

186187
fn main() {
187-
#[cfg(feature = "std")]
188188
{
189189
let (energy_before, energy_after) = nbody::run(1000);
190190
println!("Energy before: {}", energy_before);

library/portable-simd/crates/core_simd/src/intrinsics.rs

+8-26
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,21 @@ extern "platform-intrinsic" {
3939

4040
/// fptoui/fptosi/uitofp/sitofp
4141
pub(crate) fn simd_cast<T, U>(x: T) -> U;
42+
/// follows Rust's `T as U` semantics, including saturating float casts
43+
/// which amounts to the same as `simd_cast` for many cases
44+
#[cfg(not(bootstrap))]
45+
pub(crate) fn simd_as<T, U>(x: T) -> U;
4246

4347
/// neg/fneg
4448
pub(crate) fn simd_neg<T>(x: T) -> T;
4549

4650
/// fabs
4751
pub(crate) fn simd_fabs<T>(x: T) -> T;
4852

53+
// minnum/maxnum
54+
pub(crate) fn simd_fmin<T>(x: T, y: T) -> T;
55+
pub(crate) fn simd_fmax<T>(x: T, y: T) -> T;
56+
4957
pub(crate) fn simd_eq<T, U>(x: T, y: T) -> U;
5058
pub(crate) fn simd_ne<T, U>(x: T, y: T) -> U;
5159
pub(crate) fn simd_lt<T, U>(x: T, y: T) -> U;
@@ -87,29 +95,3 @@ extern "platform-intrinsic" {
8795
#[allow(unused)]
8896
pub(crate) fn simd_select_bitmask<M, T>(m: M, a: T, b: T) -> T;
8997
}
90-
91-
#[cfg(feature = "std")]
92-
mod std {
93-
extern "platform-intrinsic" {
94-
// ceil
95-
pub(crate) fn simd_ceil<T>(x: T) -> T;
96-
97-
// floor
98-
pub(crate) fn simd_floor<T>(x: T) -> T;
99-
100-
// round
101-
pub(crate) fn simd_round<T>(x: T) -> T;
102-
103-
// trunc
104-
pub(crate) fn simd_trunc<T>(x: T) -> T;
105-
106-
// fsqrt
107-
pub(crate) fn simd_fsqrt<T>(x: T) -> T;
108-
109-
// fma
110-
pub(crate) fn simd_fma<T>(x: T, y: T, z: T) -> T;
111-
}
112-
}
113-
114-
#[cfg(feature = "std")]
115-
pub(crate) use crate::simd::intrinsics::std::*;

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

+30-12
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
)]
1313
mod mask_impl;
1414

15+
use crate::simd::intrinsics;
1516
use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
1617
use core::cmp::Ordering;
17-
use core::fmt;
18+
use core::{fmt, mem};
1819

1920
mod sealed {
2021
use super::*;
@@ -105,22 +106,39 @@ where
105106
Self(mask_impl::Mask::splat(value))
106107
}
107108

108-
/// Converts an array to a SIMD vector.
109+
/// Converts an array of bools to a SIMD mask.
109110
pub fn from_array(array: [bool; LANES]) -> Self {
110-
let mut vector = Self::splat(false);
111-
for (i, v) in array.iter().enumerate() {
112-
vector.set(i, *v);
111+
// SAFETY: Rust's bool has a layout of 1 byte (u8) with a value of
112+
// true: 0b_0000_0001
113+
// false: 0b_0000_0000
114+
// Thus, an array of bools is also a valid array of bytes: [u8; N]
115+
// This would be hypothetically valid as an "in-place" transmute,
116+
// but these are "dependently-sized" types, so copy elision it is!
117+
unsafe {
118+
let bytes: [u8; LANES] = mem::transmute_copy(&array);
119+
let bools: Simd<i8, LANES> =
120+
intrinsics::simd_ne(Simd::from_array(bytes), Simd::splat(0u8));
121+
Mask::from_int_unchecked(intrinsics::simd_cast(bools))
113122
}
114-
vector
115123
}
116124

117-
/// Converts a SIMD vector to an array.
125+
/// Converts a SIMD mask to an array of bools.
118126
pub fn to_array(self) -> [bool; LANES] {
119-
let mut array = [false; LANES];
120-
for (i, v) in array.iter_mut().enumerate() {
121-
*v = self.test(i);
127+
// This follows mostly the same logic as from_array.
128+
// SAFETY: Rust's bool has a layout of 1 byte (u8) with a value of
129+
// true: 0b_0000_0001
130+
// false: 0b_0000_0000
131+
// Thus, an array of bools is also a valid array of bytes: [u8; N]
132+
// Since our masks are equal to integers where all bits are set,
133+
// we can simply convert them to i8s, and then bitand them by the
134+
// bitpattern for Rust's "true" bool.
135+
// This would be hypothetically valid as an "in-place" transmute,
136+
// but these are "dependently-sized" types, so copy elision it is!
137+
unsafe {
138+
let mut bytes: Simd<i8, LANES> = intrinsics::simd_cast(self.to_int());
139+
bytes &= Simd::splat(1i8);
140+
mem::transmute_copy(&bytes)
122141
}
123-
array
124142
}
125143

126144
/// Converts a vector of integers to a mask, where 0 represents `false` and -1
@@ -516,7 +534,7 @@ pub type mask16x8 = Mask<i16, 8>;
516534
pub type mask16x16 = Mask<i16, 16>;
517535

518536
/// Vector of 32 16-bit masks
519-
pub type mask16x32 = Mask<i32, 32>;
537+
pub type mask16x32 = Mask<i16, 32>;
520538

521539
/// Vector of two 32-bit masks
522540
pub type mask32x2 = Mask<i32, 2>;

0 commit comments

Comments
 (0)