Various bug fixes

This commit is contained in:
Caleb Zulawski 2021-03-06 02:14:58 -05:00
parent 93ce1c1a59
commit 07247a001f
9 changed files with 180 additions and 18 deletions

View File

@ -12,11 +12,11 @@ mod permute;
#[macro_use]
mod transmute;
mod comparisons;
mod fmt;
mod intrinsics;
mod ops;
mod round;
mod comparisons;
mod math;

View File

@ -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,

View File

@ -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])

View File

@ -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 }

View File

@ -1,3 +1,5 @@
#![feature(is_subnormal)]
#[macro_use]
mod ops_macros;
impl_float_tests! { SimdF32, f32, i32 }

View File

@ -1,3 +1,5 @@
#![feature(is_subnormal)]
#[macro_use]
mod ops_macros;
impl_float_tests! { SimdF64, f64, i64 }

View File

@ -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,

View File

@ -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),* } => {
$(

View File

@ -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 {
}
)*
}
}
}