Skip to content

Commit 07247a0

Browse files
committed
Various bug fixes
1 parent 93ce1c1 commit 07247a0

File tree

9 files changed

+180
-18
lines changed

9 files changed

+180
-18
lines changed

Diff for: crates/core_simd/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ mod permute;
1212
#[macro_use]
1313
mod transmute;
1414

15+
mod comparisons;
1516
mod fmt;
1617
mod intrinsics;
1718
mod ops;
1819
mod round;
19-
mod comparisons;
2020

2121
mod math;
2222

Diff for: crates/core_simd/src/masks/mod.rs

+35
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,28 @@ macro_rules! define_opaque_mask {
2828
Self(<$inner_ty>::splat(value))
2929
}
3030

31+
/// Converts an array to a SIMD vector.
32+
pub fn from_array(array: [bool; LANES]) -> Self {
33+
let mut vector = Self::splat(false);
34+
let mut i = 0;
35+
while i < $lanes {
36+
vector.set(i, array[i]);
37+
i += 1;
38+
}
39+
vector
40+
}
41+
42+
/// Converts a SIMD vector to an array.
43+
pub fn to_array(self) -> [bool; LANES] {
44+
let mut array = [false; LANES];
45+
let mut i = 0;
46+
while i < $lanes {
47+
array[i] = self.test(i);
48+
i += 1;
49+
}
50+
array
51+
}
52+
3153
/// Tests the value of the specified lane.
3254
///
3355
/// # Panics
@@ -85,6 +107,19 @@ macro_rules! define_opaque_mask {
85107
}
86108
}
87109

110+
// vector/array conversion
111+
impl<const $lanes: usize> From<[bool; $lanes]> for $name<$lanes> where $bits_ty: crate::LanesAtMost64 {
112+
fn from(array: [bool; $lanes]) -> Self {
113+
Self::from_array(array)
114+
}
115+
}
116+
117+
impl <const $lanes: usize> From<$name<$lanes>> for [bool; $lanes] where $bits_ty: crate::LanesAtMost64 {
118+
fn from(vector: $name<$lanes>) -> Self {
119+
vector.to_array()
120+
}
121+
}
122+
88123
impl<const $lanes: usize> Copy for $name<$lanes>
89124
where
90125
$inner_ty: Copy,

Diff for: crates/core_simd/src/vector/float.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,21 @@ macro_rules! impl_float_vector {
4747
/// `+0.0`, `NaN`s with positive sign bit and positive infinity.
4848
#[inline]
4949
pub fn is_sign_positive(self) -> crate::$mask_ty<LANES> {
50-
let sign_bits = self.to_bits() & crate::$bits_ty::splat((!0 >> 1) + 1);
51-
sign_bits.lanes_gt(crate::$bits_ty::splat(0))
50+
!self.is_sign_negative()
5251
}
5352

5453
/// Returns true for each lane if it has a negative sign, including
5554
/// `-0.0`, `NaN`s with negative sign bit and negative infinity.
5655
#[inline]
5756
pub fn is_sign_negative(self) -> crate::$mask_ty<LANES> {
58-
!self.is_sign_positive()
57+
let sign_bits = self.to_bits() & crate::$bits_ty::splat((!0 >> 1) + 1);
58+
sign_bits.lanes_gt(crate::$bits_ty::splat(0))
5959
}
6060

6161
/// Returns true for each lane if its value is `NaN`.
6262
#[inline]
6363
pub fn is_nan(self) -> crate::$mask_ty<LANES> {
64-
self.lanes_eq(self)
64+
self.lanes_ne(self)
6565
}
6666

6767
/// Returns true for each lane if its value is positive infinity or negative infinity.
@@ -79,8 +79,8 @@ macro_rules! impl_float_vector {
7979
/// Returns true for each lane if its value is subnormal.
8080
#[inline]
8181
pub fn is_subnormal(self) -> crate::$mask_ty<LANES> {
82-
let mantissa_mask = crate::$bits_ty::splat((1 << (<$type>::MANTISSA_DIGITS - 1)) - 1);
83-
self.abs().lanes_ne(Self::splat(0.0)) & (self.to_bits() & mantissa_mask).lanes_eq(crate::$bits_ty::splat(0))
82+
let exponent_mask = crate::$bits_ty::splat(!0 << <$type>::MANTISSA_DIGITS);
83+
self.abs().lanes_ne(Self::splat(0.0)) & (self.to_bits() & exponent_mask).lanes_eq(crate::$bits_ty::splat(0))
8484
}
8585

8686
/// Returns true for each lane if its value is neither neither zero, infinite,
@@ -93,7 +93,6 @@ macro_rules! impl_float_vector {
9393
};
9494
}
9595

96-
9796
/// A SIMD vector of containing `LANES` `f32` values.
9897
#[repr(simd)]
9998
pub struct SimdF32<const LANES: usize>([f32; LANES])

Diff for: crates/core_simd/src/vector/int.rs

+23-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
/// Implements additional integer traits (Eq, Ord, Hash) on the specified vector `$name`, holding multiple `$lanes` of `$type`.
44
macro_rules! impl_integer_vector {
5-
{ $name:ident, $type:ty } => {
5+
{ $name:ident, $type:ty, $mask_ty:ident, $mask_impl_ty:ident } => {
66
impl_vector! { $name, $type }
77

88
impl<const LANES: usize> Eq for $name<LANES> where Self: crate::LanesAtMost64 {}
@@ -24,6 +24,22 @@ macro_rules! impl_integer_vector {
2424
self.as_slice().hash(state)
2525
}
2626
}
27+
28+
impl<const LANES: usize> $name<LANES>
29+
where
30+
Self: crate::LanesAtMost64,
31+
crate::$mask_impl_ty<LANES>: crate::LanesAtMost64,
32+
{
33+
/// Returns true for each positive lane and false if it is zero or negative.
34+
pub fn is_positive(self) -> crate::$mask_ty<LANES> {
35+
self.lanes_gt(Self::splat(0))
36+
}
37+
38+
/// Returns true for each negative lane and false if it is zero or positive.
39+
pub fn is_negative(self) -> crate::$mask_ty<LANES> {
40+
self.lanes_lt(Self::splat(0))
41+
}
42+
}
2743
}
2844
}
2945

@@ -33,7 +49,7 @@ pub struct SimdIsize<const LANES: usize>([isize; LANES])
3349
where
3450
Self: crate::LanesAtMost64;
3551

36-
impl_integer_vector! { SimdIsize, isize }
52+
impl_integer_vector! { SimdIsize, isize, MaskSize, SimdIsize }
3753

3854
#[cfg(target_pointer_width = "32")]
3955
from_transmute_x86! { unsafe isizex4 => __m128i }
@@ -53,7 +69,7 @@ pub struct SimdI128<const LANES: usize>([i128; LANES])
5369
where
5470
Self: crate::LanesAtMost64;
5571

56-
impl_integer_vector! { SimdI128, i128 }
72+
impl_integer_vector! { SimdI128, i128, Mask128, SimdI128 }
5773

5874
from_transmute_x86! { unsafe i128x2 => __m256i }
5975
//from_transmute_x86! { unsafe i128x4 => __m512i }
@@ -64,7 +80,7 @@ pub struct SimdI16<const LANES: usize>([i16; LANES])
6480
where
6581
Self: crate::LanesAtMost64;
6682

67-
impl_integer_vector! { SimdI16, i16 }
83+
impl_integer_vector! { SimdI16, i16, Mask16, SimdI16 }
6884

6985
from_transmute_x86! { unsafe i16x8 => __m128i }
7086
from_transmute_x86! { unsafe i16x16 => __m256i }
@@ -76,7 +92,7 @@ pub struct SimdI32<const LANES: usize>([i32; LANES])
7692
where
7793
Self: crate::LanesAtMost64;
7894

79-
impl_integer_vector! { SimdI32, i32 }
95+
impl_integer_vector! { SimdI32, i32, Mask32, SimdI32 }
8096

8197
from_transmute_x86! { unsafe i32x4 => __m128i }
8298
from_transmute_x86! { unsafe i32x8 => __m256i }
@@ -88,7 +104,7 @@ pub struct SimdI64<const LANES: usize>([i64; LANES])
88104
where
89105
Self: crate::LanesAtMost64;
90106

91-
impl_integer_vector! { SimdI64, i64 }
107+
impl_integer_vector! { SimdI64, i64, Mask64, SimdI64 }
92108

93109
from_transmute_x86! { unsafe i64x2 => __m128i }
94110
from_transmute_x86! { unsafe i64x4 => __m256i }
@@ -100,7 +116,7 @@ pub struct SimdI8<const LANES: usize>([i8; LANES])
100116
where
101117
Self: crate::LanesAtMost64;
102118

103-
impl_integer_vector! { SimdI8, i8 }
119+
impl_integer_vector! { SimdI8, i8, Mask8, SimdI8 }
104120

105121
from_transmute_x86! { unsafe i8x16 => __m128i }
106122
from_transmute_x86! { unsafe i8x32 => __m256i }

Diff for: crates/core_simd/tests/f32_ops.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![feature(is_subnormal)]
2+
13
#[macro_use]
24
mod ops_macros;
35
impl_float_tests! { SimdF32, f32, i32 }

Diff for: crates/core_simd/tests/f64_ops.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![feature(is_subnormal)]
2+
13
#[macro_use]
24
mod ops_macros;
35
impl_float_tests! { SimdF64, f64, i64 }

Diff for: crates/core_simd/tests/ops_macros.rs

+73-1
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,27 @@ macro_rules! impl_signed_tests {
147147
test_helpers::test_lanes! {
148148
fn neg<const LANES: usize>() {
149149
test_helpers::test_unary_elementwise(
150-
&<Vector<LANES> as core::ops::Neg>::neg,
150+
&<Vector::<LANES> as core::ops::Neg>::neg,
151151
&<Scalar as core::ops::Neg>::neg,
152152
&|x| !x.contains(&Scalar::MIN),
153153
);
154154
}
155+
156+
fn is_positive<const LANES: usize>() {
157+
test_helpers::test_unary_mask_elementwise(
158+
&Vector::<LANES>::is_positive,
159+
&Scalar::is_positive,
160+
&|_| true,
161+
);
162+
}
163+
164+
fn is_negative<const LANES: usize>() {
165+
test_helpers::test_unary_mask_elementwise(
166+
&Vector::<LANES>::is_negative,
167+
&Scalar::is_negative,
168+
&|_| true,
169+
);
170+
}
155171
}
156172

157173
test_helpers::test_lanes_panic! {
@@ -285,6 +301,62 @@ macro_rules! impl_float_tests {
285301
}
286302

287303
test_helpers::test_lanes! {
304+
fn is_sign_positive<const LANES: usize>() {
305+
test_helpers::test_unary_mask_elementwise(
306+
&Vector::<LANES>::is_sign_positive,
307+
&Scalar::is_sign_positive,
308+
&|_| true,
309+
);
310+
}
311+
312+
fn is_sign_negative<const LANES: usize>() {
313+
test_helpers::test_unary_mask_elementwise(
314+
&Vector::<LANES>::is_sign_negative,
315+
&Scalar::is_sign_negative,
316+
&|_| true,
317+
);
318+
}
319+
320+
fn is_finite<const LANES: usize>() {
321+
test_helpers::test_unary_mask_elementwise(
322+
&Vector::<LANES>::is_finite,
323+
&Scalar::is_finite,
324+
&|_| true,
325+
);
326+
}
327+
328+
fn is_infinite<const LANES: usize>() {
329+
test_helpers::test_unary_mask_elementwise(
330+
&Vector::<LANES>::is_infinite,
331+
&Scalar::is_infinite,
332+
&|_| true,
333+
);
334+
}
335+
336+
fn is_nan<const LANES: usize>() {
337+
test_helpers::test_unary_mask_elementwise(
338+
&Vector::<LANES>::is_nan,
339+
&Scalar::is_nan,
340+
&|_| true,
341+
);
342+
}
343+
344+
fn is_normal<const LANES: usize>() {
345+
test_helpers::test_unary_mask_elementwise(
346+
&Vector::<LANES>::is_normal,
347+
&Scalar::is_normal,
348+
&|_| true,
349+
);
350+
}
351+
352+
fn is_subnormal<const LANES: usize>() {
353+
test_helpers::test_unary_mask_elementwise(
354+
&Vector::<LANES>::is_subnormal,
355+
&Scalar::is_subnormal,
356+
&|_| true,
357+
);
358+
}
359+
288360
fn abs<const LANES: usize>() {
289361
test_helpers::test_unary_elementwise(
290362
&Vector::<LANES>::abs,

Diff for: crates/test_helpers/src/biteq.rs

+10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ pub trait BitEq {
55
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result;
66
}
77

8+
impl BitEq for bool {
9+
fn biteq(&self, other: &Self) -> bool {
10+
self == other
11+
}
12+
13+
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
14+
write!(f, "{:?}", self)
15+
}
16+
}
17+
818
macro_rules! impl_integer_biteq {
919
{ $($type:ty),* } => {
1020
$(

Diff for: crates/test_helpers/src/lib.rs

+28-2
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,32 @@ pub fn test_unary_elementwise<Scalar, ScalarResult, Vector, VectorResult, const
124124
});
125125
}
126126

127+
/// Test a unary vector function against a unary scalar function, applied elementwise.
128+
#[inline(never)]
129+
pub fn test_unary_mask_elementwise<Scalar, Vector, Mask, const LANES: usize>(
130+
fv: &dyn Fn(Vector) -> Mask,
131+
fs: &dyn Fn(Scalar) -> bool,
132+
check: &dyn Fn([Scalar; LANES]) -> bool,
133+
) where
134+
Scalar: Copy + Default + core::fmt::Debug + DefaultStrategy,
135+
Vector: Into<[Scalar; LANES]> + From<[Scalar; LANES]> + Copy,
136+
Mask: Into<[bool; LANES]> + From<[bool; LANES]> + Copy,
137+
{
138+
test_1(&|x: [Scalar; LANES]| {
139+
proptest::prop_assume!(check(x));
140+
let result_1: [bool; LANES] = fv(x.into()).into();
141+
let result_2: [bool; LANES] = {
142+
let mut result = [false; LANES];
143+
for (i, o) in x.iter().zip(result.iter_mut()) {
144+
*o = fs(*i);
145+
}
146+
result
147+
};
148+
crate::prop_assert_biteq!(result_1, result_2);
149+
Ok(())
150+
});
151+
}
152+
127153
/// Test a binary vector function against a binary scalar function, applied elementwise.
128154
#[inline(never)]
129155
pub fn test_binary_elementwise<
@@ -307,7 +333,7 @@ macro_rules! test_lanes {
307333
}
308334
)*
309335
}
310-
}
336+
}
311337

312338
/// Expand a const-generic `#[should_panic]` test into separate tests for each possible lane count.
313339
#[macro_export]
@@ -382,4 +408,4 @@ macro_rules! test_lanes_panic {
382408
}
383409
)*
384410
}
385-
}
411+
}

0 commit comments

Comments
 (0)