Implement abs, to_bits, and from_bits for float vectors
This commit is contained in:
parent
0b39351ba5
commit
866971adf5
4 changed files with 106 additions and 7 deletions
|
|
@ -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]); } => {
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue