From cea143bacc1409a7a97b60a766d8db410899c10a Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Mon, 6 Nov 2017 14:42:20 +0100 Subject: [PATCH] implement missing std::ops --- src/macros.rs | 303 +++++++++++++++++++++++++++++++++++++++++++++-- src/simd_llvm.rs | 1 + src/v128.rs | 13 ++ src/v256.rs | 13 ++ src/v512.rs | 13 ++ src/v64.rs | 13 ++ 6 files changed, 346 insertions(+), 10 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index 3d4dbd798b..c2018acc40 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -166,13 +166,7 @@ macro_rules! define_common_ops { unsafe { simd_mul(self, other) } } } - )+ - } -} -macro_rules! define_float_ops { - ($($ty:ident),+) => { - $( impl ::std::ops::Div for $ty { type Output = Self; #[inline(always)] @@ -180,6 +174,50 @@ macro_rules! define_float_ops { unsafe { simd_div(self, other) } } } + + impl ::std::ops::Rem for $ty { + type Output = Self; + #[inline(always)] + fn rem(self, other: Self) -> Self { + unsafe { simd_rem(self, other) } + } + } + + impl ::std::ops::AddAssign for $ty { + #[inline(always)] + fn add_assign(&mut self, other: Self) { + *self = *self + other; + } + } + + impl ::std::ops::SubAssign for $ty { + #[inline(always)] + fn sub_assign(&mut self, other: Self) { + *self = *self - other; + } + } + + impl ::std::ops::MulAssign for $ty { + #[inline(always)] + fn mul_assign(&mut self, other: Self) { + *self = *self * other; + } + } + + impl ::std::ops::DivAssign for $ty { + #[inline(always)] + fn div_assign(&mut self, other: Self) { + *self = *self / other; + } + } + + impl ::std::ops::RemAssign for $ty { + #[inline(always)] + fn rem_assign(&mut self, other: Self) { + *self = *self % other; + } + } + )+ } } @@ -201,13 +239,63 @@ macro_rules! define_shifts { unsafe { simd_shr(self, $ty::splat(other as $elem)) } } } + + impl ::std::ops::ShlAssign<$by> for $ty { + #[inline(always)] + fn shl_assign(&mut self, other: $by) { + *self = *self << other; + } + } + impl ::std::ops::ShrAssign<$by> for $ty { + #[inline(always)] + fn shr_assign(&mut self, other: $by) { + *self = *self >> other; + } + } + )+ } } +macro_rules! define_float_ops { + ($($ty:ident),+) => { + $( + impl ::std::ops::Neg for $ty { + type Output = Self; + #[inline(always)] + fn neg(self) -> Self { + Self::splat(-1.0) * self + } + } + )+ + }; +} + +macro_rules! define_signed_integer_ops { + ($($ty:ident),+) => { + $( + impl ::std::ops::Neg for $ty { + type Output = Self; + #[inline(always)] + fn neg(self) -> Self { + Self::splat(-1) * self + } + } + )+ + }; +} + macro_rules! define_integer_ops { ($(($ty:ident, $elem:ident)),+) => { $( + impl ::std::ops::Not for $ty { + type Output = Self; + #[inline(always)] + fn not(self) -> Self { + $ty::splat(!0) ^ self + } + } + impl ::std::ops::BitAnd for $ty { type Output = Self; #[inline(always)] @@ -229,13 +317,25 @@ macro_rules! define_integer_ops { unsafe { simd_xor(self, other) } } } - impl ::std::ops::Not for $ty { - type Output = Self; + impl ::std::ops::BitAndAssign for $ty { #[inline(always)] - fn not(self) -> Self { - $ty::splat(!0) ^ self + fn bitand_assign(&mut self, other: Self) { + *self = *self & other; + } + } + impl ::std::ops::BitOrAssign for $ty { + #[inline(always)] + fn bitor_assign(&mut self, other: Self) { + *self = *self | other; + } + } + impl ::std::ops::BitXorAssign for $ty { + #[inline(always)] + fn bitxor_assign(&mut self, other: Self) { + *self = *self ^ other; } } + define_shifts!( $ty, $elem, u8, u16, u32, u64, usize, @@ -321,3 +421,186 @@ mod tests { assert!(cfg_feature_enabled!("sse")); } } + + +#[cfg(test)] +#[macro_export] +macro_rules! test_arithmetic_ { + ($tn:ident, $zero:expr, $one:expr, $two:expr, $four:expr) => { + { + let z = $tn::splat($zero); + let o = $tn::splat($one); + let t = $tn::splat($two); + let f = $tn::splat($four); + + // add + assert_eq!(z + z, z); + assert_eq!(o + z, o); + assert_eq!(t + z, t); + assert_eq!(t + t, f); + // sub + assert_eq!(z - z, z); + assert_eq!(o - z, o); + assert_eq!(t - z, t); + assert_eq!(f - t, t); + assert_eq!(f - o - o, t); + // mul + assert_eq!(z * z, z); + assert_eq!(z * o, z); + assert_eq!(z * t, z); + assert_eq!(o * t, t); + assert_eq!(t * t, f); + // div + assert_eq!(z / o, z); + assert_eq!(t / o, t); + assert_eq!(f / o, f); + assert_eq!(t / t, o); + assert_eq!(f / t, t); + // rem + assert_eq!(o % o, z); + assert_eq!(f % t, z); + + { + let mut v = z; + assert_eq!(v, z); + v += o; // add_assign + assert_eq!(v, o); + v -= o; // sub_assign + assert_eq!(v, z); + v = t; + v *= o; // mul_assign + assert_eq!(v, t); + v *= t; + assert_eq!(v, f); + v /= o; // div_assign + assert_eq!(v, f); + v /= t; + assert_eq!(v, t); + v %= t; // rem_assign + assert_eq!(v, z); + } + } + }; + } + +#[cfg(test)] +#[macro_export] + macro_rules! test_neg_ { + ($tn:ident, $zero:expr, $one:expr, $two:expr, $four:expr) => { + { + let z = $tn::splat($zero); + let o = $tn::splat($one); + let t = $tn::splat($two); + let f = $tn::splat($four); + + let nz = $tn::splat(-$zero); + let no = $tn::splat(-$one); + let nt = $tn::splat(-$two); + let nf = $tn::splat(-$four); + + assert_eq!(-z, nz); + assert_eq!(-o, no); + assert_eq!(-t, nt); + assert_eq!(-f, nf); + } + }; + } + +#[cfg(test)] +#[macro_export] +macro_rules! test_bit_arithmetic_ { + ($tn:ident) => { + { + let z = $tn::splat(0); + let o = $tn::splat(1); + let t = $tn::splat(2); + let f = $tn::splat(4); + let m = $tn::splat(!z.extract(0)); + + // shr + assert_eq!(o >> 1, z); + assert_eq!(t >> 1, o); + assert_eq!(f >> 1, t); + // shl + assert_eq!(o << 1, t); + assert_eq!(o << 2, f); + assert_eq!(t << 1, f); + // bitand + assert_eq!(o & o, o); + assert_eq!(t & t, t); + assert_eq!(t & o, z); + // bitor + assert_eq!(o | o, o); + assert_eq!(t | t, t); + assert_eq!(z | o, o); + // bitxor + assert_eq!(o ^ o, z); + assert_eq!(t ^ t, z); + assert_eq!(z ^ o, o); + // not + assert_eq!(!z, m); + assert_eq!(!m, z); + + { // shr_assign + let mut v = o; + v >>= 1; + assert_eq!(v, z); + } + { // shl_assign + let mut v = o; + v <<= 1; + assert_eq!(v, t); + } + { // and_assign + let mut v = o; + v &= t; + assert_eq!(v, z); + } + { // or_assign + let mut v = z; + v |= o; + assert_eq!(v, o); + } + { // xor_assign + let mut v = z; + v ^= o; + assert_eq!(v, o); + } + } + }; +} + + +#[cfg(test)] +#[macro_export] + macro_rules! test_ops_si { + ($($tn:ident),+) => { + $( + test_arithmetic_!($tn, 0, 1, 2, 4); + test_neg_!($tn, 0, 1, 2, 4); + test_bit_arithmetic_!($tn); + )+ + }; + } + +#[cfg(test)] +#[macro_export] + macro_rules! test_ops_ui { + ($($tn:ident),+) => { + $( + test_arithmetic_!($tn, 0, 1, 2, 4); + test_bit_arithmetic_!($tn); + )+ + }; + } + +#[cfg(test)] +#[macro_export] + macro_rules! test_ops_f { + ($($tn:ident),+) => { + $( + test_arithmetic_!($tn, 0., 1., 2., 4.); + test_neg_!($tn, 0., 1., 2., 4.); + )+ + }; + } diff --git a/src/simd_llvm.rs b/src/simd_llvm.rs index 66a1cc8768..c4ae8a2a90 100644 --- a/src/simd_llvm.rs +++ b/src/simd_llvm.rs @@ -25,6 +25,7 @@ extern "platform-intrinsic" { pub fn simd_sub(x: T, y: T) -> T; pub fn simd_mul(x: T, y: T) -> T; pub fn simd_div(x: T, y: T) -> T; + pub fn simd_rem(x: T, y: T) -> T; pub fn simd_shl(x: T, y: T) -> T; pub fn simd_shr(x: T, y: T) -> T; pub fn simd_and(x: T, y: T) -> T; diff --git a/src/v128.rs b/src/v128.rs index 9677cf9ab9..cf98340d83 100644 --- a/src/v128.rs +++ b/src/v128.rs @@ -74,6 +74,7 @@ define_integer_ops!( (u8x16, u8), (i8x16, i8) ); +define_signed_integer_ops!(i64x2, i32x4, i16x8, i8x16); define_casts!( (f64x2, f32x2, as_f32x2), (f64x2, u64x2, as_u64x2), @@ -94,3 +95,15 @@ define_casts!( (u8x16, i8x16, as_i8x16), (i8x16, u8x16, as_u8x16) ); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn operators() { + test_ops_si!(i8x16, i16x8, i32x4, i64x2); + test_ops_ui!(u8x16, u16x8, u32x4, u64x2); + test_ops_f!(f32x4, f64x2); + } +} diff --git a/src/v256.rs b/src/v256.rs index 2687e18325..1f02bad0f2 100644 --- a/src/v256.rs +++ b/src/v256.rs @@ -98,6 +98,7 @@ define_integer_ops!( (u8x32, u8), (i8x32, i8) ); +define_signed_integer_ops!(i64x4, i32x8, i16x16, i8x32); define_casts!( (f64x4, f32x4, as_f32x4), (f64x4, u64x4, as_u64x4), @@ -117,3 +118,15 @@ define_casts!( (u8x32, i8x32, as_i8x32), (i8x32, u8x32, as_u8x32) ); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn operators() { + test_ops_si!(i8x32, i16x16, i32x8, i64x4); + test_ops_ui!(u8x32, u16x16, u32x8, u64x4); + test_ops_f!(f32x8, f64x4); + } +} diff --git a/src/v512.rs b/src/v512.rs index e763ef8ffa..b52668903e 100644 --- a/src/v512.rs +++ b/src/v512.rs @@ -144,6 +144,7 @@ define_integer_ops!( (u8x64, u8), (i8x64, i8) ); +define_signed_integer_ops!(i64x8, i32x16, i16x32, i8x64); define_casts!( (f64x8, f32x8, as_f32x8), (f64x8, u64x8, as_u64x8), @@ -163,3 +164,15 @@ define_casts!( (u8x64, i8x64, as_i8x64), (i8x64, u8x64, as_u8x64) ); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn operators() { + test_ops_si!(i8x64, i16x32, i32x16, i64x8); + test_ops_ui!(u8x64, u16x32, u32x16, u64x8); + test_ops_f!(f32x16, f64x8); + } +} diff --git a/src/v64.rs b/src/v64.rs index 9802fcf764..0df2e878d6 100644 --- a/src/v64.rs +++ b/src/v64.rs @@ -46,6 +46,7 @@ define_integer_ops!( (u8x8, u8), (i8x8, i8) ); +define_signed_integer_ops!(i32x2, i16x4, i8x8); define_casts!( (f32x2, f64x2, as_f64x2), (f32x2, u32x2, as_u32x2), @@ -65,3 +66,15 @@ define_casts!( (u16x4, u32x4, as_u32x4), (u32x2, u64x2, as_u64x2) ); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn operators() { + test_ops_si!(i8x8, i16x4, i32x2); + test_ops_ui!(u8x8, u16x4, u32x2); + test_ops_f!(f32x2); + } +}