Implement abs, to_bits, and from_bits for float vectors

This commit is contained in:
Thom Chiovoloni 2020-10-06 11:21:54 -07:00
parent 0b39351ba5
commit 866971adf5
4 changed files with 106 additions and 7 deletions

View file

@ -270,6 +270,52 @@ macro_rules! define_vector {
}
}
/// Implements inherent methods for a float vector `$name` containing multiple
/// `$lanes` of float `$type`, which uses `$bits_ty` as its binary
/// representation. Called from `define_float_vector!`.
macro_rules! impl_float_vector {
{ $name:path => [$type:ty; $lanes:literal]; bits $bits_ty:ty; } => {
impl $name {
/// Raw transmutation to an unsigned integer vector type with the
/// same size and number of lanes.
#[inline]
pub fn to_bits(self) -> $bits_ty {
unsafe { core::mem::transmute(self) }
}
/// Raw transmutation from an unsigned integer vector type with the
/// same size and number of lanes.
#[inline]
pub fn from_bits(bits: $bits_ty) -> Self {
unsafe { core::mem::transmute(bits) }
}
/// Produces a vector where every lane has the absolute value of the
/// equivalently-indexed lane in `self`.
#[inline]
pub fn abs(self) -> Self {
let no_sign = <$bits_ty>::splat(!0 >> 1);
let abs = unsafe { crate::intrinsics::simd_and(self.to_bits(), no_sign) };
Self::from_bits(abs)
}
}
};
}
/// Defines a float vector `$name` containing multiple `$lanes` of float
/// `$type`, which uses `$bits_ty` as its binary representation.
macro_rules! define_float_vector {
{ $(#[$attr:meta])* struct $name:ident([$type:ty; $lanes:tt]); bits $bits_ty:ty; } => {
define_vector! {
$(#[$attr])*
struct $name([$type; $lanes]);
}
impl_float_vector! { $name => [$type; $lanes]; bits $bits_ty; }
}
}
/// Defines an integer vector `$name` containing multiple `$lanes` of integer `$type`.
macro_rules! define_integer_vector {
{ $(#[$attr:meta])* struct $name:ident([$type:ty; $lanes:tt]); } => {

View file

@ -1,23 +1,29 @@
define_vector! {
define_float_vector! {
/// Vector of two `f32` values
struct f32x2([f32; 2]);
bits crate::u32x2;
}
define_vector! {
define_float_vector! {
/// Vector of four `f32` values
struct f32x4([f32; 4]);
bits crate::u32x4;
}
define_vector! {
define_float_vector! {
/// Vector of eight `f32` values
struct f32x8([f32; 8]);
bits crate::u32x8;
}
define_vector! {
define_float_vector! {
/// Vector of 16 `f32` values
struct f32x16([f32; 16]);
bits crate::u32x16;
}
from_transmute_x86! { unsafe f32x4 => __m128 }
from_transmute_x86! { unsafe f32x8 => __m256 }
//from_transmute_x86! { unsafe f32x16 => __m512 }

View file

@ -1,16 +1,19 @@
define_vector! {
define_float_vector! {
/// Vector of two `f64` values
struct f64x2([f64; 2]);
bits crate::u64x2;
}
define_vector! {
define_float_vector! {
/// Vector of four `f64` values
struct f64x4([f64; 4]);
bits crate::u64x4;
}
define_vector! {
define_float_vector! {
/// Vector of eight `f64` values
struct f64x8([f64; 8]);
bits crate::u64x8;
}
from_transmute_x86! { unsafe f64x2 => __m128d }

View file

@ -21,6 +21,26 @@ macro_rules! float_tests {
const A: [$scalar; 16] = [0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15.];
const B: [$scalar; 16] = [16., 17., 18., 19., 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31.];
const C: [$scalar; 16] = [
-0.0,
0.0,
-1.0,
1.0,
<$scalar>::MIN,
<$scalar>::MAX,
<$scalar>::INFINITY,
-<$scalar>::INFINITY,
<$scalar>::MIN_POSITIVE,
-<$scalar>::MIN_POSITIVE,
<$scalar>::EPSILON,
-<$scalar>::EPSILON,
0.0 / 0.0,
-0.0 / 0.0,
// Still not sure if wasm can have weird nans, or I'd check them
// too. Until then
1.0 / 3.0,
-1.0 / 4.0
];
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
@ -264,6 +284,30 @@ macro_rules! float_tests {
let expected = apply_unary_lanewise(v, core::ops::Neg::neg);
assert_biteq!(-v, expected);
}
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn abs_negative() {
let v = -from_slice(&A);
let expected = apply_unary_lanewise(v, <$scalar>::abs);
assert_biteq!(v.abs(), expected);
}
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn abs_positive() {
let v = from_slice(&B);
let expected = apply_unary_lanewise(v, <$scalar>::abs);
assert_biteq!(v.abs(), expected);
}
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn abs_odd_floats() {
let v = from_slice(&C);
let expected = apply_unary_lanewise(v, <$scalar>::abs);
assert_biteq!(v.abs(), expected);
}
}
}
}