Skip to content

Commit

Permalink
Merge pull request rust-lang#27 from thomcc/abs_from_to_bits
Browse files Browse the repository at this point in the history
Implement abs, to_bits, and from_bits for float vectors
  • Loading branch information
Lokathor committed Oct 7, 2020
2 parents 0b39351 + 8d3d616 commit a1c327a
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 7 deletions.
45 changes: 45 additions & 0 deletions crates/core_simd/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,51 @@ 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);
Self::from_bits(self.to_bits() & no_sign)
}
}
};
}

/// 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]); } => {
Expand Down
14 changes: 10 additions & 4 deletions crates/core_simd/src/vectors_f32.rs
Original file line number Diff line number Diff line change
@@ -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 }


9 changes: 6 additions & 3 deletions crates/core_simd/src/vectors_f64.rs
Original file line number Diff line number Diff line change
@@ -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 }
Expand Down
49 changes: 49 additions & 0 deletions crates/core_simd/tests/ops_impl/float_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,32 @@ macro_rules! float_tests {
value
}

fn slice_chunks(slice: &[$scalar]) -> impl Iterator<Item = core_simd::$vector> + '_ {
let lanes = core::mem::size_of::<core_simd::$vector>() / core::mem::size_of::<$scalar>();
slice.chunks_exact(lanes).map(from_slice)
}

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>::NEG_INFINITY,
<$scalar>::MIN_POSITIVE,
-<$scalar>::MIN_POSITIVE,
<$scalar>::EPSILON,
-<$scalar>::EPSILON,
<$scalar>::NAN,
-<$scalar>::NAN,
// TODO: Would be nice to check sNaN...
100.0 / 3.0,
-100.0 / 3.0,
];

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
Expand Down Expand Up @@ -264,6 +288,31 @@ 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() {
for v in slice_chunks(&C) {
let expected = apply_unary_lanewise(v, <$scalar>::abs);
assert_biteq!(v.abs(), expected);
}
}
}
}
}

0 comments on commit a1c327a

Please sign in to comment.