Various bug fixes
This commit is contained in:
parent
93ce1c1a59
commit
07247a001f
@ -12,11 +12,11 @@ mod permute;
|
||||
#[macro_use]
|
||||
mod transmute;
|
||||
|
||||
mod comparisons;
|
||||
mod fmt;
|
||||
mod intrinsics;
|
||||
mod ops;
|
||||
mod round;
|
||||
mod comparisons;
|
||||
|
||||
mod math;
|
||||
|
||||
|
@ -28,6 +28,28 @@ macro_rules! define_opaque_mask {
|
||||
Self(<$inner_ty>::splat(value))
|
||||
}
|
||||
|
||||
/// Converts an array to a SIMD vector.
|
||||
pub fn from_array(array: [bool; LANES]) -> Self {
|
||||
let mut vector = Self::splat(false);
|
||||
let mut i = 0;
|
||||
while i < $lanes {
|
||||
vector.set(i, array[i]);
|
||||
i += 1;
|
||||
}
|
||||
vector
|
||||
}
|
||||
|
||||
/// Converts a SIMD vector to an array.
|
||||
pub fn to_array(self) -> [bool; LANES] {
|
||||
let mut array = [false; LANES];
|
||||
let mut i = 0;
|
||||
while i < $lanes {
|
||||
array[i] = self.test(i);
|
||||
i += 1;
|
||||
}
|
||||
array
|
||||
}
|
||||
|
||||
/// Tests the value of the specified lane.
|
||||
///
|
||||
/// # Panics
|
||||
@ -85,6 +107,19 @@ macro_rules! define_opaque_mask {
|
||||
}
|
||||
}
|
||||
|
||||
// vector/array conversion
|
||||
impl<const $lanes: usize> From<[bool; $lanes]> for $name<$lanes> where $bits_ty: crate::LanesAtMost64 {
|
||||
fn from(array: [bool; $lanes]) -> Self {
|
||||
Self::from_array(array)
|
||||
}
|
||||
}
|
||||
|
||||
impl <const $lanes: usize> From<$name<$lanes>> for [bool; $lanes] where $bits_ty: crate::LanesAtMost64 {
|
||||
fn from(vector: $name<$lanes>) -> Self {
|
||||
vector.to_array()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const $lanes: usize> Copy for $name<$lanes>
|
||||
where
|
||||
$inner_ty: Copy,
|
||||
|
@ -47,21 +47,21 @@ macro_rules! impl_float_vector {
|
||||
/// `+0.0`, `NaN`s with positive sign bit and positive infinity.
|
||||
#[inline]
|
||||
pub fn is_sign_positive(self) -> crate::$mask_ty<LANES> {
|
||||
let sign_bits = self.to_bits() & crate::$bits_ty::splat((!0 >> 1) + 1);
|
||||
sign_bits.lanes_gt(crate::$bits_ty::splat(0))
|
||||
!self.is_sign_negative()
|
||||
}
|
||||
|
||||
/// Returns true for each lane if it has a negative sign, including
|
||||
/// `-0.0`, `NaN`s with negative sign bit and negative infinity.
|
||||
#[inline]
|
||||
pub fn is_sign_negative(self) -> crate::$mask_ty<LANES> {
|
||||
!self.is_sign_positive()
|
||||
let sign_bits = self.to_bits() & crate::$bits_ty::splat((!0 >> 1) + 1);
|
||||
sign_bits.lanes_gt(crate::$bits_ty::splat(0))
|
||||
}
|
||||
|
||||
/// Returns true for each lane if its value is `NaN`.
|
||||
#[inline]
|
||||
pub fn is_nan(self) -> crate::$mask_ty<LANES> {
|
||||
self.lanes_eq(self)
|
||||
self.lanes_ne(self)
|
||||
}
|
||||
|
||||
/// Returns true for each lane if its value is positive infinity or negative infinity.
|
||||
@ -79,8 +79,8 @@ macro_rules! impl_float_vector {
|
||||
/// Returns true for each lane if its value is subnormal.
|
||||
#[inline]
|
||||
pub fn is_subnormal(self) -> crate::$mask_ty<LANES> {
|
||||
let mantissa_mask = crate::$bits_ty::splat((1 << (<$type>::MANTISSA_DIGITS - 1)) - 1);
|
||||
self.abs().lanes_ne(Self::splat(0.0)) & (self.to_bits() & mantissa_mask).lanes_eq(crate::$bits_ty::splat(0))
|
||||
let exponent_mask = crate::$bits_ty::splat(!0 << <$type>::MANTISSA_DIGITS);
|
||||
self.abs().lanes_ne(Self::splat(0.0)) & (self.to_bits() & exponent_mask).lanes_eq(crate::$bits_ty::splat(0))
|
||||
}
|
||||
|
||||
/// Returns true for each lane if its value is neither neither zero, infinite,
|
||||
@ -93,7 +93,6 @@ macro_rules! impl_float_vector {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// A SIMD vector of containing `LANES` `f32` values.
|
||||
#[repr(simd)]
|
||||
pub struct SimdF32<const LANES: usize>([f32; LANES])
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
/// Implements additional integer traits (Eq, Ord, Hash) on the specified vector `$name`, holding multiple `$lanes` of `$type`.
|
||||
macro_rules! impl_integer_vector {
|
||||
{ $name:ident, $type:ty } => {
|
||||
{ $name:ident, $type:ty, $mask_ty:ident, $mask_impl_ty:ident } => {
|
||||
impl_vector! { $name, $type }
|
||||
|
||||
impl<const LANES: usize> Eq for $name<LANES> where Self: crate::LanesAtMost64 {}
|
||||
@ -24,6 +24,22 @@ macro_rules! impl_integer_vector {
|
||||
self.as_slice().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const LANES: usize> $name<LANES>
|
||||
where
|
||||
Self: crate::LanesAtMost64,
|
||||
crate::$mask_impl_ty<LANES>: crate::LanesAtMost64,
|
||||
{
|
||||
/// Returns true for each positive lane and false if it is zero or negative.
|
||||
pub fn is_positive(self) -> crate::$mask_ty<LANES> {
|
||||
self.lanes_gt(Self::splat(0))
|
||||
}
|
||||
|
||||
/// Returns true for each negative lane and false if it is zero or positive.
|
||||
pub fn is_negative(self) -> crate::$mask_ty<LANES> {
|
||||
self.lanes_lt(Self::splat(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +49,7 @@ pub struct SimdIsize<const LANES: usize>([isize; LANES])
|
||||
where
|
||||
Self: crate::LanesAtMost64;
|
||||
|
||||
impl_integer_vector! { SimdIsize, isize }
|
||||
impl_integer_vector! { SimdIsize, isize, MaskSize, SimdIsize }
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
from_transmute_x86! { unsafe isizex4 => __m128i }
|
||||
@ -53,7 +69,7 @@ pub struct SimdI128<const LANES: usize>([i128; LANES])
|
||||
where
|
||||
Self: crate::LanesAtMost64;
|
||||
|
||||
impl_integer_vector! { SimdI128, i128 }
|
||||
impl_integer_vector! { SimdI128, i128, Mask128, SimdI128 }
|
||||
|
||||
from_transmute_x86! { unsafe i128x2 => __m256i }
|
||||
//from_transmute_x86! { unsafe i128x4 => __m512i }
|
||||
@ -64,7 +80,7 @@ pub struct SimdI16<const LANES: usize>([i16; LANES])
|
||||
where
|
||||
Self: crate::LanesAtMost64;
|
||||
|
||||
impl_integer_vector! { SimdI16, i16 }
|
||||
impl_integer_vector! { SimdI16, i16, Mask16, SimdI16 }
|
||||
|
||||
from_transmute_x86! { unsafe i16x8 => __m128i }
|
||||
from_transmute_x86! { unsafe i16x16 => __m256i }
|
||||
@ -76,7 +92,7 @@ pub struct SimdI32<const LANES: usize>([i32; LANES])
|
||||
where
|
||||
Self: crate::LanesAtMost64;
|
||||
|
||||
impl_integer_vector! { SimdI32, i32 }
|
||||
impl_integer_vector! { SimdI32, i32, Mask32, SimdI32 }
|
||||
|
||||
from_transmute_x86! { unsafe i32x4 => __m128i }
|
||||
from_transmute_x86! { unsafe i32x8 => __m256i }
|
||||
@ -88,7 +104,7 @@ pub struct SimdI64<const LANES: usize>([i64; LANES])
|
||||
where
|
||||
Self: crate::LanesAtMost64;
|
||||
|
||||
impl_integer_vector! { SimdI64, i64 }
|
||||
impl_integer_vector! { SimdI64, i64, Mask64, SimdI64 }
|
||||
|
||||
from_transmute_x86! { unsafe i64x2 => __m128i }
|
||||
from_transmute_x86! { unsafe i64x4 => __m256i }
|
||||
@ -100,7 +116,7 @@ pub struct SimdI8<const LANES: usize>([i8; LANES])
|
||||
where
|
||||
Self: crate::LanesAtMost64;
|
||||
|
||||
impl_integer_vector! { SimdI8, i8 }
|
||||
impl_integer_vector! { SimdI8, i8, Mask8, SimdI8 }
|
||||
|
||||
from_transmute_x86! { unsafe i8x16 => __m128i }
|
||||
from_transmute_x86! { unsafe i8x32 => __m256i }
|
||||
|
@ -1,3 +1,5 @@
|
||||
#![feature(is_subnormal)]
|
||||
|
||||
#[macro_use]
|
||||
mod ops_macros;
|
||||
impl_float_tests! { SimdF32, f32, i32 }
|
||||
|
@ -1,3 +1,5 @@
|
||||
#![feature(is_subnormal)]
|
||||
|
||||
#[macro_use]
|
||||
mod ops_macros;
|
||||
impl_float_tests! { SimdF64, f64, i64 }
|
||||
|
@ -147,11 +147,27 @@ macro_rules! impl_signed_tests {
|
||||
test_helpers::test_lanes! {
|
||||
fn neg<const LANES: usize>() {
|
||||
test_helpers::test_unary_elementwise(
|
||||
&<Vector<LANES> as core::ops::Neg>::neg,
|
||||
&<Vector::<LANES> as core::ops::Neg>::neg,
|
||||
&<Scalar as core::ops::Neg>::neg,
|
||||
&|x| !x.contains(&Scalar::MIN),
|
||||
);
|
||||
}
|
||||
|
||||
fn is_positive<const LANES: usize>() {
|
||||
test_helpers::test_unary_mask_elementwise(
|
||||
&Vector::<LANES>::is_positive,
|
||||
&Scalar::is_positive,
|
||||
&|_| true,
|
||||
);
|
||||
}
|
||||
|
||||
fn is_negative<const LANES: usize>() {
|
||||
test_helpers::test_unary_mask_elementwise(
|
||||
&Vector::<LANES>::is_negative,
|
||||
&Scalar::is_negative,
|
||||
&|_| true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
test_helpers::test_lanes_panic! {
|
||||
@ -285,6 +301,62 @@ macro_rules! impl_float_tests {
|
||||
}
|
||||
|
||||
test_helpers::test_lanes! {
|
||||
fn is_sign_positive<const LANES: usize>() {
|
||||
test_helpers::test_unary_mask_elementwise(
|
||||
&Vector::<LANES>::is_sign_positive,
|
||||
&Scalar::is_sign_positive,
|
||||
&|_| true,
|
||||
);
|
||||
}
|
||||
|
||||
fn is_sign_negative<const LANES: usize>() {
|
||||
test_helpers::test_unary_mask_elementwise(
|
||||
&Vector::<LANES>::is_sign_negative,
|
||||
&Scalar::is_sign_negative,
|
||||
&|_| true,
|
||||
);
|
||||
}
|
||||
|
||||
fn is_finite<const LANES: usize>() {
|
||||
test_helpers::test_unary_mask_elementwise(
|
||||
&Vector::<LANES>::is_finite,
|
||||
&Scalar::is_finite,
|
||||
&|_| true,
|
||||
);
|
||||
}
|
||||
|
||||
fn is_infinite<const LANES: usize>() {
|
||||
test_helpers::test_unary_mask_elementwise(
|
||||
&Vector::<LANES>::is_infinite,
|
||||
&Scalar::is_infinite,
|
||||
&|_| true,
|
||||
);
|
||||
}
|
||||
|
||||
fn is_nan<const LANES: usize>() {
|
||||
test_helpers::test_unary_mask_elementwise(
|
||||
&Vector::<LANES>::is_nan,
|
||||
&Scalar::is_nan,
|
||||
&|_| true,
|
||||
);
|
||||
}
|
||||
|
||||
fn is_normal<const LANES: usize>() {
|
||||
test_helpers::test_unary_mask_elementwise(
|
||||
&Vector::<LANES>::is_normal,
|
||||
&Scalar::is_normal,
|
||||
&|_| true,
|
||||
);
|
||||
}
|
||||
|
||||
fn is_subnormal<const LANES: usize>() {
|
||||
test_helpers::test_unary_mask_elementwise(
|
||||
&Vector::<LANES>::is_subnormal,
|
||||
&Scalar::is_subnormal,
|
||||
&|_| true,
|
||||
);
|
||||
}
|
||||
|
||||
fn abs<const LANES: usize>() {
|
||||
test_helpers::test_unary_elementwise(
|
||||
&Vector::<LANES>::abs,
|
||||
|
@ -5,6 +5,16 @@ pub trait BitEq {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result;
|
||||
}
|
||||
|
||||
impl BitEq for bool {
|
||||
fn biteq(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_integer_biteq {
|
||||
{ $($type:ty),* } => {
|
||||
$(
|
||||
|
@ -124,6 +124,32 @@ pub fn test_unary_elementwise<Scalar, ScalarResult, Vector, VectorResult, const
|
||||
});
|
||||
}
|
||||
|
||||
/// Test a unary vector function against a unary scalar function, applied elementwise.
|
||||
#[inline(never)]
|
||||
pub fn test_unary_mask_elementwise<Scalar, Vector, Mask, const LANES: usize>(
|
||||
fv: &dyn Fn(Vector) -> Mask,
|
||||
fs: &dyn Fn(Scalar) -> bool,
|
||||
check: &dyn Fn([Scalar; LANES]) -> bool,
|
||||
) where
|
||||
Scalar: Copy + Default + core::fmt::Debug + DefaultStrategy,
|
||||
Vector: Into<[Scalar; LANES]> + From<[Scalar; LANES]> + Copy,
|
||||
Mask: Into<[bool; LANES]> + From<[bool; LANES]> + Copy,
|
||||
{
|
||||
test_1(&|x: [Scalar; LANES]| {
|
||||
proptest::prop_assume!(check(x));
|
||||
let result_1: [bool; LANES] = fv(x.into()).into();
|
||||
let result_2: [bool; LANES] = {
|
||||
let mut result = [false; LANES];
|
||||
for (i, o) in x.iter().zip(result.iter_mut()) {
|
||||
*o = fs(*i);
|
||||
}
|
||||
result
|
||||
};
|
||||
crate::prop_assert_biteq!(result_1, result_2);
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
/// Test a binary vector function against a binary scalar function, applied elementwise.
|
||||
#[inline(never)]
|
||||
pub fn test_binary_elementwise<
|
||||
@ -307,7 +333,7 @@ macro_rules! test_lanes {
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Expand a const-generic `#[should_panic]` test into separate tests for each possible lane count.
|
||||
#[macro_export]
|
||||
@ -382,4 +408,4 @@ macro_rules! test_lanes_panic {
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user