diff --git a/.gitignore b/.gitignore index 1519564..b833f45 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store +.vs/ /target /Cargo.lock /bench/bench diff --git a/.travis.yml b/.travis.yml index dfac6df..0ef33bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,9 @@ matrix: env: CARGO_FEATURES="simd" - rust: nightly env: CARGO_FEATURES="serde simd" + - rust: nightly-2019-01-01 + # an old nightly build where "simd" still worked and "specialization" + env: CARGO_FEATURES="simd" allow_failures: - rust: nightly diff --git a/CHANGELOG.md b/CHANGELOG.md index ee86bd8..cf67592 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed + + - Refactored dependencies of experimental "specialization" feature into + default_fn! macro to reduce code duplication and complexity. Currently + only needed for non-functional SIMD feature. + - Refactored SIMD code into separate source files. See README.md for details. + ### Added - Add `VectorN::zip` and `PointN::zip` diff --git a/Cargo.toml b/Cargo.toml index dfebc25..1563bf3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,8 +26,8 @@ mint = { version = "0.5", optional = true } num-traits = "0.2" rand = { version = "0.7", optional = true } serde = { version = "1.0", features = ["serde_derive"], optional = true } -simd = { version = "0.2", optional = true } +simd = { version = "0.2", optional = true } # works only in rust toolchain up to 1.32 [dev-dependencies] -glium = "0.23" +# glium = "0.23" # causes problems with nightly-2019-01-01 needed for testing "simd" serde_json = "1.0" diff --git a/README.md b/README.md index a87d8ad..2b7ef92 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,13 @@ and `v.zy()` produces a ```rust Vector2 { x: 3.0, y: 2.0 } ``` +### SIMD optimizations + +The current SIMD support depends on the deprecated "simd" package as well +as the unstable "specialization" feature. To build this code, a pre-1.33 nightly +build of Rust is required, e.g. 2019-01-01-nightly. Though the code is not +useful in its present form, it has some worth preserving as starting point +for a future migration (see https://github.com/rustgd/cgmath/issues/490). ## Limitations diff --git a/src/conv.rs b/src/conv.rs index 833ebef..a6abd42 100644 --- a/src/conv.rs +++ b/src/conv.rs @@ -4,7 +4,8 @@ //! For example, when declaring `glium` uniforms, we need to convert to fixed //! length arrays. We can use the `Into` trait directly, but it is rather ugly! //! -//! ```rust +//! --- Doc-test disabled because glium causes problems with nightly-2019-01-01 needed for "simd" +//! ` ` `rust //! #[macro_use] //! extern crate glium; //! extern crate cgmath; @@ -22,11 +23,12 @@ //! // Yuck!! (ノಥ益ಥ)ノ ┻━┻ //! }; //! # } -//! ``` +//! ` ` ` //! //! Instead, we can use the conversion functions from the `conv` module: //! -//! ```rust +//! --- Doc-test disabled because glium causes problems nightly-2019-01-01 needed for "simd" +//! ` ` `rust //! #[macro_use] //! extern crate glium; //! extern crate cgmath; @@ -45,7 +47,7 @@ //! // ┬─┬ノ( º _ ºノ) //! }; //! # } -//! ``` +//! ` ` ` /// Force a conversion into a 2-element array. #[inline] diff --git a/src/lib.rs b/src/lib.rs index 30d2a66..9e406f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,8 +99,15 @@ mod structure; mod matrix; mod quaternion; + +#[cfg(feature = "simd")] +mod quaternion_simd; + mod vector; +#[cfg(feature = "simd")] +mod vector_simd; + mod angle; mod euler; mod point; diff --git a/src/macros.rs b/src/macros.rs index 573c597..bbcf924 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -17,6 +17,16 @@ #![macro_use] +#[cfg(feature = "simd")] +macro_rules! default_fn { + { $($tt:tt)* } => { default fn $( $tt )* }; +} + +#[cfg(not(feature = "simd"))] +macro_rules! default_fn { + { $($tt:tt)* } => { fn $( $tt )* }; +} + /// Generates a binary operator implementation for the permutations of by-ref and by-val macro_rules! impl_operator { // When it is an unary operator @@ -26,17 +36,17 @@ macro_rules! impl_operator { impl<$S: $Constraint> $Op for $Lhs { type Output = $Output; #[inline] - fn $op(self) -> $Output { + default_fn!($op(self) -> $Output { let $x = self; $body - } + }); } impl<'a, $S: $Constraint> $Op for &'a $Lhs { type Output = $Output; #[inline] - fn $op(self) -> $Output { + default_fn!($op(self) -> $Output { let $x = self; $body - } + }); } }; // When the right operand is a scalar @@ -46,17 +56,17 @@ macro_rules! impl_operator { impl<$S: $Constraint> $Op<$Rhs> for $Lhs { type Output = $Output; #[inline] - fn $op(self, other: $Rhs) -> $Output { + default_fn!($op(self, other: $Rhs) -> $Output { let ($lhs, $rhs) = (self, other); $body - } + }); } impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs { type Output = $Output; #[inline] - fn $op(self, other: $Rhs) -> $Output { + default_fn!($op(self, other: $Rhs) -> $Output { let ($lhs, $rhs) = (self, other); $body - } + }); } }; // When the right operand is a compound type @@ -66,33 +76,33 @@ macro_rules! impl_operator { impl<$S: $Constraint> $Op<$Rhs> for $Lhs { type Output = $Output; #[inline] - fn $op(self, other: $Rhs) -> $Output { + default_fn!( $op(self, other: $Rhs) -> $Output { let ($lhs, $rhs) = (self, other); $body - } + }); } impl<'a, $S: $Constraint> $Op<&'a $Rhs> for $Lhs { type Output = $Output; #[inline] - fn $op(self, other: &'a $Rhs) -> $Output { + default_fn!( $op(self, other: &'a $Rhs) -> $Output { let ($lhs, $rhs) = (self, other); $body - } + }); } impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs { type Output = $Output; #[inline] - fn $op(self, other: $Rhs) -> $Output { + default_fn!( $op(self, other: $Rhs) -> $Output { let ($lhs, $rhs) = (self, other); $body - } + }); } impl<'a, 'b, $S: $Constraint> $Op<&'a $Rhs> for &'b $Lhs { type Output = $Output; #[inline] - fn $op(self, other: &'a $Rhs) -> $Output { + default_fn!( $op(self, other: &'a $Rhs) -> $Output { let ($lhs, $rhs) = (self, other); $body - } + }); } }; // When the left operand is a scalar @@ -102,17 +112,17 @@ macro_rules! impl_operator { impl $Op<$Rhs<$S>> for $Lhs { type Output = $Output; #[inline] - fn $op(self, other: $Rhs<$S>) -> $Output { + default_fn!( $op(self, other: $Rhs<$S>) -> $Output { let ($lhs, $rhs) = (self, other); $body - } + }); } impl<'a> $Op<&'a $Rhs<$S>> for $Lhs { type Output = $Output; #[inline] - fn $op(self, other: &'a $Rhs<$S>) -> $Output { + default_fn!( $op(self, other: &'a $Rhs<$S>) -> $Output { let ($lhs, $rhs) = (self, other); $body - } + }); } }; } @@ -123,7 +133,7 @@ macro_rules! impl_assignment_operator { }) => { impl<$S: $Constraint + $Op<$S>> $Op<$Rhs> for $Lhs { #[inline] - fn $op(&mut $lhs, $rhs: $Rhs) $body + default_fn!( $op(&mut $lhs, $rhs: $Rhs) $body ); } }; } @@ -255,118 +265,6 @@ macro_rules! impl_index_operators { } } -#[cfg(feature = "simd")] -macro_rules! impl_operator_default { - // When it is an unary operator - (<$S:ident: $Constraint:ident> $Op:ident for $Lhs:ty { - fn $op:ident($x:ident) -> $Output:ty { $body:expr } - }) => { - impl<$S: $Constraint> $Op for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self) -> $Output { - let $x = self; $body - } - } - - impl<'a, $S: $Constraint> $Op for &'a $Lhs { - type Output = $Output; - #[inline] - default fn $op(self) -> $Output { - let $x = self; $body - } - } - }; - // When the right operand is a scalar - (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ident> for $Lhs:ty { - fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } - }) => { - impl<$S: $Constraint> $Op<$Rhs> for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - }; - // When the right operand is a compound type - (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ty> for $Lhs:ty { - fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } - }) => { - impl<$S: $Constraint> $Op<$Rhs> for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a, $S: $Constraint> $Op<&'a $Rhs> for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: &'a $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a, 'b, $S: $Constraint> $Op<&'a $Rhs> for &'b $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: &'a $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - }; - // When the left operand is a scalar - ($Op:ident<$Rhs:ident<$S:ident>> for $Lhs:ty { - fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } - }) => { - impl $Op<$Rhs<$S>> for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: $Rhs<$S>) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a> $Op<&'a $Rhs<$S>> for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: &'a $Rhs<$S>) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - }; -} - -#[cfg(feature = "simd")] -macro_rules! impl_assignment_operator_default { - (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ty> for $Lhs:ty { - fn $op:ident(&mut $lhs:ident, $rhs:ident) $body:block - }) => { - impl<$S: $Constraint + $Op<$S>> $Op<$Rhs> for $Lhs { - #[inline] - default fn $op(&mut $lhs, $rhs: $Rhs) $body - } - }; -} - /// Generates a binary operator implementation for the permutations of by-ref and by-val, for simd #[cfg(feature = "simd")] macro_rules! impl_operator_simd { diff --git a/src/matrix.rs b/src/matrix.rs index 8b50535..abaf861 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -1520,21 +1520,21 @@ impl From> for Quaternion { impl fmt::Debug for Matrix2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Matrix2 ")); + write!(f, "Matrix2 ")?; <[[S; 2]; 2] as fmt::Debug>::fmt(self.as_ref(), f) } } impl fmt::Debug for Matrix3 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Matrix3 ")); + write!(f, "Matrix3 ")?; <[[S; 3]; 3] as fmt::Debug>::fmt(self.as_ref(), f) } } impl fmt::Debug for Matrix4 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Matrix4 ")); + write!(f, "Matrix4 ")?; <[[S; 4]; 4] as fmt::Debug>::fmt(self.as_ref(), f) } } diff --git a/src/point.rs b/src/point.rs index 17d7bb7..d5aad79 100644 --- a/src/point.rs +++ b/src/point.rs @@ -370,21 +370,21 @@ impl_mint_conversions!(Point3 { x, y, z }, Point3); impl fmt::Debug for Point1 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Point1 ")); + write!(f, "Point1 ")?; <[S; 1] as fmt::Debug>::fmt(self.as_ref(), f) } } impl fmt::Debug for Point2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Point2 ")); + write!(f, "Point2 ")?; <[S; 2] as fmt::Debug>::fmt(self.as_ref(), f) } } impl fmt::Debug for Point3 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Point3 ")); + write!(f, "Point3 ")?; <[S; 3] as fmt::Debug>::fmt(self.as_ref(), f) } } diff --git a/src/quaternion.rs b/src/quaternion.rs index 3bd6b42..f267002 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -35,9 +35,6 @@ use point::Point3; use rotation::{Basis3, Rotation, Rotation3}; use vector::Vector3; -#[cfg(feature = "simd")] -use simd::f32x4 as Simdf32x4; - #[cfg(feature = "mint")] use mint; @@ -55,30 +52,6 @@ pub struct Quaternion { pub v: Vector3, } -#[cfg(feature = "simd")] -impl From for Quaternion { - #[inline] - fn from(f: Simdf32x4) -> Self { - unsafe { - let mut ret: Self = mem::uninitialized(); - { - let ret_mut: &mut [f32; 4] = ret.as_mut(); - f.store(ret_mut.as_mut(), 0 as usize); - } - ret - } - } -} - -#[cfg(feature = "simd")] -impl Into for Quaternion { - #[inline] - fn into(self) -> Simdf32x4 { - let self_ref: &[f32; 4] = self.as_ref(); - Simdf32x4::load(self_ref.as_ref(), 0 as usize) - } -} - impl Quaternion { /// Construct a new quaternion from one scalar component and three /// imaginary components. @@ -260,31 +233,11 @@ impl Quaternion { } } -#[cfg(not(feature = "simd"))] impl InnerSpace for Quaternion { #[inline] - fn dot(self, other: Quaternion) -> S { + default_fn!( dot(self, other: Quaternion) -> S { self.s * other.s + self.v.dot(other.v) - } -} - -#[cfg(feature = "simd")] -impl InnerSpace for Quaternion { - #[inline] - default fn dot(self, other: Quaternion) -> S { - self.s * other.s + self.v.dot(other.v) - } -} - -#[cfg(feature = "simd")] -impl InnerSpace for Quaternion { - #[inline] - fn dot(self, other: Quaternion) -> f32 { - let lhs: Simdf32x4 = self.into(); - let rhs: Simdf32x4 = other.into(); - let r = lhs * rhs; - r.extract(0) + r.extract(1) + r.extract(2) + r.extract(3) - } + } ); } impl From> for Quaternion @@ -311,113 +264,32 @@ where } } -#[cfg(not(feature = "simd"))] impl_operator!( Neg for Quaternion { fn neg(quat) -> Quaternion { Quaternion::from_sv(-quat.s, -quat.v) } }); -#[cfg(feature = "simd")] -impl_operator_default!( Neg for Quaternion { - fn neg(quat) -> Quaternion { - Quaternion::from_sv(-quat.s, -quat.v) - } -}); - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdf32x4]; Neg for Quaternion { - fn neg(lhs) -> Quaternion { - (-lhs).into() - } - } -} - -#[cfg(not(feature = "simd"))] impl_operator!( Mul for Quaternion { fn mul(lhs, rhs) -> Quaternion { Quaternion::from_sv(lhs.s * rhs, lhs.v * rhs) } }); -#[cfg(feature = "simd")] -impl_operator_default!( Mul for Quaternion { - fn mul(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s * rhs, lhs.v * rhs) - } -}); - -#[cfg(feature = "simd")] -impl_operator_simd!{@rs - [Simdf32x4]; Mul for Quaternion { - fn mul(lhs, rhs) -> Quaternion { - (lhs * rhs).into() - } - } -} - -#[cfg(not(feature = "simd"))] impl_assignment_operator!( MulAssign for Quaternion { fn mul_assign(&mut self, scalar) { self.s *= scalar; self.v *= scalar; } }); -#[cfg(feature = "simd")] -impl_assignment_operator_default!( MulAssign for Quaternion { - fn mul_assign(&mut self, scalar) { self.s *= scalar; self.v *= scalar; } -}); - -#[cfg(feature = "simd")] -impl MulAssign for Quaternion { - fn mul_assign(&mut self, other: f32) { - let s: Simdf32x4 = (*self).into(); - let other = Simdf32x4::splat(other); - *self = (s * other).into(); - } -} - -#[cfg(not(feature = "simd"))] impl_operator!( Div for Quaternion { fn div(lhs, rhs) -> Quaternion { Quaternion::from_sv(lhs.s / rhs, lhs.v / rhs) } }); -#[cfg(feature = "simd")] -impl_operator_default!( Div for Quaternion { - fn div(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s / rhs, lhs.v / rhs) - } -}); - -#[cfg(feature = "simd")] -impl_operator_simd!{@rs - [Simdf32x4]; Div for Quaternion { - fn div(lhs, rhs) -> Quaternion { - (lhs / rhs).into() - } - } -} - -#[cfg(not(feature = "simd"))] impl_assignment_operator!( DivAssign for Quaternion { fn div_assign(&mut self, scalar) { self.s /= scalar; self.v /= scalar; } }); -#[cfg(feature = "simd")] -impl_assignment_operator_default!( DivAssign for Quaternion { - fn div_assign(&mut self, scalar) { self.s /= scalar; self.v /= scalar; } -}); - -#[cfg(feature = "simd")] -impl DivAssign for Quaternion { - fn div_assign(&mut self, other: f32) { - let s: Simdf32x4 = (*self).into(); - let other = Simdf32x4::splat(other); - *self = (s / other).into(); - } -} - impl_operator!( Rem for Quaternion { fn rem(lhs, rhs) -> Quaternion { Quaternion::from_sv(lhs.s % rhs, lhs.v % rhs) @@ -437,93 +309,26 @@ impl_operator!( Mul > for Quaternion { }} }); -#[cfg(not(feature = "simd"))] impl_operator!( Add > for Quaternion { fn add(lhs, rhs) -> Quaternion { Quaternion::from_sv(lhs.s + rhs.s, lhs.v + rhs.v) } }); -#[cfg(feature = "simd")] -impl_operator_default!( Add > for Quaternion { - fn add(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s + rhs.s, lhs.v + rhs.v) - } -}); - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdf32x4]; Add> for Quaternion { - fn add(lhs, rhs) -> Quaternion { - (lhs + rhs).into() - } - } -} - -#[cfg(not(feature = "simd"))] impl_assignment_operator!( AddAssign > for Quaternion { fn add_assign(&mut self, other) { self.s += other.s; self.v += other.v; } }); -#[cfg(feature = "simd")] -impl_assignment_operator_default!( AddAssign > for Quaternion { - fn add_assign(&mut self, other) { self.s += other.s; self.v += other.v; } -}); - -#[cfg(feature = "simd")] -impl AddAssign for Quaternion { - #[inline] - fn add_assign(&mut self, rhs: Self) { - let s: Simdf32x4 = (*self).into(); - let rhs: Simdf32x4 = rhs.into(); - *self = (s + rhs).into(); - } -} - -#[cfg(not(feature = "simd"))] impl_operator!( Sub > for Quaternion { fn sub(lhs, rhs) -> Quaternion { Quaternion::from_sv(lhs.s - rhs.s, lhs.v - rhs.v) } }); -#[cfg(feature = "simd")] -impl_operator_default!( Sub > for Quaternion { - fn sub(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s - rhs.s, lhs.v - rhs.v) - } -}); - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdf32x4]; Sub> for Quaternion { - fn sub(lhs, rhs) -> Quaternion { - (lhs - rhs).into() - } - } -} - -#[cfg(not(feature = "simd"))] impl_assignment_operator!( SubAssign > for Quaternion { fn sub_assign(&mut self, other) { self.s -= other.s; self.v -= other.v; } }); -#[cfg(feature = "simd")] -impl_assignment_operator_default!( SubAssign > for Quaternion { - fn sub_assign(&mut self, other) { self.s -= other.s; self.v -= other.v; } -}); - -#[cfg(feature = "simd")] -impl SubAssign for Quaternion { - #[inline] - fn sub_assign(&mut self, rhs: Self) { - let s: Simdf32x4 = (*self).into(); - let rhs: Simdf32x4 = rhs.into(); - *self = (s - rhs).into(); - } -} - -#[cfg(not(feature = "simd"))] impl_operator!( Mul > for Quaternion { fn mul(lhs, rhs) -> Quaternion { Quaternion::new( @@ -535,39 +340,6 @@ impl_operator!( Mul > for Quaternion { } }); -#[cfg(feature = "simd")] -impl_operator_default!( Mul > for Quaternion { - fn mul(lhs, rhs) -> Quaternion { - Quaternion::new( - lhs.s * rhs.s - lhs.v.x * rhs.v.x - lhs.v.y * rhs.v.y - lhs.v.z * rhs.v.z, - lhs.s * rhs.v.x + lhs.v.x * rhs.s + lhs.v.y * rhs.v.z - lhs.v.z * rhs.v.y, - lhs.s * rhs.v.y + lhs.v.y * rhs.s + lhs.v.z * rhs.v.x - lhs.v.x * rhs.v.z, - lhs.s * rhs.v.z + lhs.v.z * rhs.s + lhs.v.x * rhs.v.y - lhs.v.y * rhs.v.x, - ) - } -}); - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdf32x4]; Mul> for Quaternion { - fn mul(lhs, rhs) -> Quaternion { - { - let p0 = Simdf32x4::splat(lhs.extract(0)) * rhs; - let p1 = Simdf32x4::splat(lhs.extract(1)) * Simdf32x4::new( - -rhs.extract(1), rhs.extract(0), -rhs.extract(3), rhs.extract(2) - ); - let p2 = Simdf32x4::splat(lhs.extract(2)) * Simdf32x4::new( - -rhs.extract(2), rhs.extract(3), rhs.extract(0), -rhs.extract(1) - ); - let p3 = Simdf32x4::splat(lhs.extract(3)) * Simdf32x4::new( - -rhs.extract(3), -rhs.extract(2), rhs.extract(1), rhs.extract(0) - ); - (p0 + p1 + p2 + p3).into() - } - } - } -} - macro_rules! impl_scalar_mul { ($S:ident) => { impl_operator!(Mul> for $S { diff --git a/src/quaternion_simd.rs b/src/quaternion_simd.rs new file mode 100644 index 0000000..83ccad8 --- /dev/null +++ b/src/quaternion_simd.rs @@ -0,0 +1,149 @@ +// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use quaternion::*; + +use structure::*; + +use std::mem; +use std::ops::*; + +use simd::f32x4 as Simdf32x4; + +impl From for Quaternion { + #[inline] + fn from(f: Simdf32x4) -> Self { + unsafe { + let mut ret: Self = mem::uninitialized(); + { + let ret_mut: &mut [f32; 4] = ret.as_mut(); + f.store(ret_mut.as_mut(), 0 as usize); + } + ret + } + } +} + +impl Into for Quaternion { + #[inline] + fn into(self) -> Simdf32x4 { + let self_ref: &[f32; 4] = self.as_ref(); + Simdf32x4::load(self_ref.as_ref(), 0 as usize) + } +} + +impl InnerSpace for Quaternion { + #[inline] + fn dot(self, other: Quaternion) -> f32 { + let lhs: Simdf32x4 = self.into(); + let rhs: Simdf32x4 = other.into(); + let r = lhs * rhs; + r.extract(0) + r.extract(1) + r.extract(2) + r.extract(3) + } +} + +impl_operator_simd!{ + [Simdf32x4]; Neg for Quaternion { + fn neg(lhs) -> Quaternion { + (-lhs).into() + } + } +} + +impl_operator_simd!{@rs + [Simdf32x4]; Mul for Quaternion { + fn mul(lhs, rhs) -> Quaternion { + (lhs * rhs).into() + } + } +} + +impl MulAssign for Quaternion { + fn mul_assign(&mut self, other: f32) { + let s: Simdf32x4 = (*self).into(); + let other = Simdf32x4::splat(other); + *self = (s * other).into(); + } +} + +impl_operator_simd!{@rs + [Simdf32x4]; Div for Quaternion { + fn div(lhs, rhs) -> Quaternion { + (lhs / rhs).into() + } + } +} + +impl DivAssign for Quaternion { + fn div_assign(&mut self, other: f32) { + let s: Simdf32x4 = (*self).into(); + let other = Simdf32x4::splat(other); + *self = (s / other).into(); + } +} + +impl_operator_simd!{ + [Simdf32x4]; Add> for Quaternion { + fn add(lhs, rhs) -> Quaternion { + (lhs + rhs).into() + } + } +} + +impl AddAssign for Quaternion { + #[inline] + fn add_assign(&mut self, rhs: Self) { + let s: Simdf32x4 = (*self).into(); + let rhs: Simdf32x4 = rhs.into(); + *self = (s + rhs).into(); + } +} + +impl_operator_simd!{ + [Simdf32x4]; Sub> for Quaternion { + fn sub(lhs, rhs) -> Quaternion { + (lhs - rhs).into() + } + } +} + +impl SubAssign for Quaternion { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + let s: Simdf32x4 = (*self).into(); + let rhs: Simdf32x4 = rhs.into(); + *self = (s - rhs).into(); + } +} + +impl_operator_simd!{ + [Simdf32x4]; Mul> for Quaternion { + fn mul(lhs, rhs) -> Quaternion { + { + let p0 = Simdf32x4::splat(lhs.extract(0)) * rhs; + let p1 = Simdf32x4::splat(lhs.extract(1)) * Simdf32x4::new( + -rhs.extract(1), rhs.extract(0), -rhs.extract(3), rhs.extract(2) + ); + let p2 = Simdf32x4::splat(lhs.extract(2)) * Simdf32x4::new( + -rhs.extract(2), rhs.extract(3), rhs.extract(0), -rhs.extract(1) + ); + let p3 = Simdf32x4::splat(lhs.extract(3)) * Simdf32x4::new( + -rhs.extract(3), -rhs.extract(2), rhs.extract(1), rhs.extract(0) + ); + (p0 + p1 + p2 + p3).into() + } + } + } +} diff --git a/src/rotation.rs b/src/rotation.rs index 86a6ea5..1949e1d 100644 --- a/src/rotation.rs +++ b/src/rotation.rs @@ -263,7 +263,7 @@ impl Rotation2 for Basis2 { impl fmt::Debug for Basis2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Basis2 ")); + write!(f, "Basis2 ")?; <[[S; 2]; 2] as fmt::Debug>::fmt(self.mat.as_ref(), f) } } @@ -445,7 +445,7 @@ where impl fmt::Debug for Basis3 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Basis3 ")); + write!(f, "Basis3 ")?; <[[S; 3]; 3] as fmt::Debug>::fmt(self.mat.as_ref(), f) } } diff --git a/src/vector.rs b/src/vector.rs index 0c758aa..1e58c4a 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -30,13 +30,6 @@ use angle::Rad; use approx; use num::{BaseFloat, BaseNum}; -#[cfg(feature = "simd")] -use simd::f32x4 as Simdf32x4; -#[cfg(feature = "simd")] -use simd::i32x4 as Simdi32x4; -#[cfg(feature = "simd")] -use simd::u32x4 as Simdu32x4; - #[cfg(feature = "mint")] use mint; @@ -217,7 +210,7 @@ macro_rules! impl_vector { type Output = $VectorN; #[inline] - fn neg(self) -> $VectorN { $VectorN::new($(-self.$field),+) } + default_fn!( neg(self) -> $VectorN { $VectorN::new($(-self.$field),+) } ); } impl approx::AbsDiffEq for $VectorN { @@ -316,30 +309,30 @@ macro_rules! impl_vector { }); impl ElementWise for $VectorN { - #[inline] fn add_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field + rhs.$field),+) } - #[inline] fn sub_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field - rhs.$field),+) } - #[inline] fn mul_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field * rhs.$field),+) } - #[inline] fn div_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field / rhs.$field),+) } + #[inline] default_fn!( add_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field + rhs.$field),+) } ); + #[inline] default_fn!( sub_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field - rhs.$field),+) } ); + #[inline] default_fn!( mul_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field * rhs.$field),+) } ); + #[inline] default_fn!( div_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field / rhs.$field),+) } ); #[inline] fn rem_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field % rhs.$field),+) } - #[inline] fn add_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field += rhs.$field);+ } - #[inline] fn sub_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field -= rhs.$field);+ } - #[inline] fn mul_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field *= rhs.$field);+ } - #[inline] fn div_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field /= rhs.$field);+ } + #[inline] default_fn!( add_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field += rhs.$field);+ } ); + #[inline] default_fn!( sub_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field -= rhs.$field);+ } ); + #[inline] default_fn!( mul_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field *= rhs.$field);+ } ); + #[inline] default_fn!( div_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field /= rhs.$field);+ } ); #[inline] fn rem_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field %= rhs.$field);+ } } impl ElementWise for $VectorN { - #[inline] fn add_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field + rhs),+) } - #[inline] fn sub_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field - rhs),+) } - #[inline] fn mul_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field * rhs),+) } - #[inline] fn div_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field / rhs),+) } + #[inline] default_fn!( add_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field + rhs),+) } ); + #[inline] default_fn!( sub_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field - rhs),+) } ); + #[inline] default_fn!( mul_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field * rhs),+) } ); + #[inline] default_fn!( div_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field / rhs),+) } ); #[inline] fn rem_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field % rhs),+) } - #[inline] fn add_assign_element_wise(&mut self, rhs: S) { $(self.$field += rhs);+ } - #[inline] fn sub_assign_element_wise(&mut self, rhs: S) { $(self.$field -= rhs);+ } - #[inline] fn mul_assign_element_wise(&mut self, rhs: S) { $(self.$field *= rhs);+ } - #[inline] fn div_assign_element_wise(&mut self, rhs: S) { $(self.$field /= rhs);+ } + #[inline] default_fn!( add_assign_element_wise(&mut self, rhs: S) { $(self.$field += rhs);+ } ); + #[inline] default_fn!( sub_assign_element_wise(&mut self, rhs: S) { $(self.$field -= rhs);+ } ); + #[inline] default_fn!( mul_assign_element_wise(&mut self, rhs: S) { $(self.$field *= rhs);+ } ); + #[inline] default_fn!( div_assign_element_wise(&mut self, rhs: S) { $(self.$field /= rhs);+ } ); #[inline] fn rem_assign_element_wise(&mut self, rhs: S) { $(self.$field %= rhs);+ } } @@ -364,256 +357,6 @@ macro_rules! impl_vector { } } -// Utility macro for generating associated functions for the vectors -// mainly duplication -#[cfg(feature = "simd")] -macro_rules! impl_vector_default { - ($VectorN:ident { $($field:ident),+ }, $n:expr, $constructor:ident) => { - impl $VectorN { - /// Construct a new vector, using the provided values. - #[inline] - pub const fn new($($field: S),+) -> $VectorN { - $VectorN { $($field: $field),+ } - } - } - - /// The short constructor. - #[inline] - pub const fn $constructor($($field: S),+) -> $VectorN { - $VectorN::new($($field),+) - } - - impl $VectorN { - /// True if all entries in the vector are finite - pub fn is_finite(&self) -> bool { - $(self.$field.is_finite())&&+ - } - } - - impl $VectorN { - /// Component-wise casting to another type. - #[inline] - pub fn cast(&self) -> Option<$VectorN> { - $( - let $field = match NumCast::from(self.$field) { - Some(field) => field, - None => return None - }; - )+ - Some($VectorN { $($field),+ }) - } - } - - impl MetricSpace for $VectorN { - type Metric = S; - - #[inline] - fn distance2(self, other: Self) -> S { - (other - self).magnitude2() - } - } - - impl Array for $VectorN { - type Element = S; - - #[inline] - fn len() -> usize { - $n - } - - #[inline] - fn from_value(scalar: S) -> $VectorN { - $VectorN { $($field: scalar),+ } - } - - #[inline] - fn sum(self) -> S where S: Add { - fold_array!(add, { $(self.$field),+ }) - } - - #[inline] - fn product(self) -> S where S: Mul { - fold_array!(mul, { $(self.$field),+ }) - } - - fn is_finite(&self) -> bool where S: BaseFloat { - $(self.$field.is_finite())&&+ - } - } - - impl Zero for $VectorN { - #[inline] - fn zero() -> $VectorN { - $VectorN::from_value(S::zero()) - } - - #[inline] - fn is_zero(&self) -> bool { - *self == $VectorN::zero() - } - } - - impl iter::Sum for $VectorN { - #[inline] - fn sum>(iter: I) -> Self { - iter.fold(Self::zero(), Add::add) - } - } - - impl<'a, S: 'a + BaseNum> iter::Sum<&'a Self> for $VectorN { - #[inline] - fn sum>(iter: I) -> Self { - iter.fold(Self::zero(), Add::add) - } - } - - impl VectorSpace for $VectorN { - type Scalar = S; - } - - impl> Neg for $VectorN { - type Output = $VectorN; - - #[inline] - default fn neg(self) -> $VectorN { $VectorN::new($(-self.$field),+) } - } - - impl approx::AbsDiffEq for $VectorN { - type Epsilon = S::Epsilon; - - #[inline] - fn default_epsilon() -> S::Epsilon { - S::default_epsilon() - } - - #[inline] - fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { - $(S::abs_diff_eq(&self.$field, &other.$field, epsilon))&&+ - } - } - - impl approx::RelativeEq for $VectorN { - #[inline] - fn default_max_relative() -> S::Epsilon { - S::default_max_relative() - } - - #[inline] - fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { - $(S::relative_eq(&self.$field, &other.$field, epsilon, max_relative))&&+ - } - } - - impl approx::UlpsEq for $VectorN { - #[inline] - fn default_max_ulps() -> u32 { - S::default_max_ulps() - } - - #[inline] - fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { - $(S::ulps_eq(&self.$field, &other.$field, epsilon, max_ulps))&&+ - } - } - - #[cfg(feature = "rand")] - impl Distribution<$VectorN> for Standard - where S: BaseFloat, - Standard: Distribution { - #[inline] - fn sample(&self, rng: &mut R) -> $VectorN { - $VectorN { $($field: rng.gen()),+ } - } - } - - impl_operator_default!( Add<$VectorN > for $VectorN { - fn add(lhs, rhs) -> $VectorN { $VectorN::new($(lhs.$field + rhs.$field),+) } - }); - - impl_assignment_operator_default!( AddAssign<$VectorN > for $VectorN { - fn add_assign(&mut self, other) { $(self.$field += other.$field);+ } - }); - - impl_operator_default!( Sub<$VectorN > for $VectorN { - fn sub(lhs, rhs) -> $VectorN { $VectorN::new($(lhs.$field - rhs.$field),+) } - }); - - impl_assignment_operator_default!( SubAssign<$VectorN > for $VectorN { - fn sub_assign(&mut self, other) { $(self.$field -= other.$field);+ } - }); - - impl_operator_default!( Mul for $VectorN { - fn mul(vector, scalar) -> $VectorN { $VectorN::new($(vector.$field * scalar),+) } - }); - - impl_assignment_operator_default!( MulAssign for $VectorN { - fn mul_assign(&mut self, scalar) { $(self.$field *= scalar);+ } - }); - - impl_operator_default!( Div for $VectorN { - fn div(vector, scalar) -> $VectorN { $VectorN::new($(vector.$field / scalar),+) } - }); - - impl_assignment_operator_default!( DivAssign for $VectorN { - fn div_assign(&mut self, scalar) { $(self.$field /= scalar);+ } - }); - - impl_operator!( Rem for $VectorN { - fn rem(vector, scalar) -> $VectorN { $VectorN::new($(vector.$field % scalar),+) } - }); - impl_assignment_operator!( RemAssign for $VectorN { - fn rem_assign(&mut self, scalar) { $(self.$field %= scalar);+ } - }); - - impl ElementWise for $VectorN { - #[inline] default fn add_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field + rhs.$field),+) } - #[inline] default fn sub_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field - rhs.$field),+) } - #[inline] default fn mul_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field * rhs.$field),+) } - #[inline] default fn div_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field / rhs.$field),+) } - #[inline] fn rem_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field % rhs.$field),+) } - - #[inline] default fn add_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field += rhs.$field);+ } - #[inline] default fn sub_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field -= rhs.$field);+ } - #[inline] default fn mul_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field *= rhs.$field);+ } - #[inline] default fn div_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field /= rhs.$field);+ } - #[inline] fn rem_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field %= rhs.$field);+ } - } - - impl ElementWise for $VectorN { - #[inline] default fn add_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field + rhs),+) } - #[inline] default fn sub_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field - rhs),+) } - #[inline] default fn mul_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field * rhs),+) } - #[inline] default fn div_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field / rhs),+) } - #[inline] fn rem_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field % rhs),+) } - - #[inline] default fn add_assign_element_wise(&mut self, rhs: S) { $(self.$field += rhs);+ } - #[inline] default fn sub_assign_element_wise(&mut self, rhs: S) { $(self.$field -= rhs);+ } - #[inline] default fn mul_assign_element_wise(&mut self, rhs: S) { $(self.$field *= rhs);+ } - #[inline] default fn div_assign_element_wise(&mut self, rhs: S) { $(self.$field /= rhs);+ } - #[inline] fn rem_assign_element_wise(&mut self, rhs: S) { $(self.$field %= rhs);+ } - } - - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops_default!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops_default!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops_default!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - - impl_index_operators!($VectorN, $n, S, usize); - impl_index_operators!($VectorN, $n, [S], Range); - impl_index_operators!($VectorN, $n, [S], RangeTo); - impl_index_operators!($VectorN, $n, [S], RangeFrom); - impl_index_operators!($VectorN, $n, [S], RangeFull); - } -} - macro_rules! impl_scalar_ops { ($VectorN:ident<$S:ident> { $($field:ident),+ }) => { impl_operator!(Mul<$VectorN<$S>> for $S { @@ -628,28 +371,10 @@ macro_rules! impl_scalar_ops { }; } -#[cfg(feature = "simd")] -macro_rules! impl_scalar_ops_default { - ($VectorN:ident<$S:ident> { $($field:ident),+ }) => { - impl_operator_default!(Mul<$VectorN<$S>> for $S { - fn mul(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar * vector.$field),+) } - }); - impl_operator_default!(Div<$VectorN<$S>> for $S { - fn div(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar / vector.$field),+) } - }); - impl_operator_default!(Rem<$VectorN<$S>> for $S { - fn rem(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar % vector.$field),+) } - }); - }; -} - impl_vector!(Vector1 { x }, 1, vec1); impl_vector!(Vector2 { x, y }, 2, vec2); impl_vector!(Vector3 { x, y, z }, 3, vec3); -#[cfg(not(feature = "simd"))] impl_vector!(Vector4 { x, y, z, w }, 4, vec4); -#[cfg(feature = "simd")] -impl_vector_default!(Vector4 { x, y, z, w }, 4, vec4); impl_fixed_array_conversions!(Vector1 { x: 0 }, 1); impl_fixed_array_conversions!(Vector2 { x: 0, y: 1 }, 2); @@ -840,431 +565,32 @@ impl InnerSpace for Vector4 { impl fmt::Debug for Vector1 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Vector1 ")); + write!(f, "Vector1 ")?; <[S; 1] as fmt::Debug>::fmt(self.as_ref(), f) } } impl fmt::Debug for Vector2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Vector2 ")); + write!(f, "Vector2 ")?; <[S; 2] as fmt::Debug>::fmt(self.as_ref(), f) } } impl fmt::Debug for Vector3 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Vector3 ")); + write!(f, "Vector3 ")?; <[S; 3] as fmt::Debug>::fmt(self.as_ref(), f) } } impl fmt::Debug for Vector4 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Vector4 ")); + write!(f, "Vector4 ")?; <[S; 4] as fmt::Debug>::fmt(self.as_ref(), f) } } -#[cfg(feature = "simd")] -impl From for Vector4 { - #[inline] - fn from(f: Simdf32x4) -> Self { - unsafe { - let mut ret: Self = mem::uninitialized(); - { - let ret_mut: &mut [f32; 4] = ret.as_mut(); - f.store(ret_mut.as_mut(), 0 as usize); - } - ret - } - } -} - -#[cfg(feature = "simd")] -impl Vector4 { - /// Compute and return the square root of each element. - #[inline] - pub fn sqrt_element_wide(self) -> Self { - let s: Simdf32x4 = self.into(); - s.sqrt().into() - } - - /// Compute and return the reciprocal of the square root of each element. - #[inline] - pub fn rsqrt_element_wide(self) -> Self { - let s: Simdf32x4 = self.into(); - s.approx_rsqrt().into() - } - - /// Compute and return the reciprocal of each element. - #[inline] - pub fn recip_element_wide(self) -> Self { - let s: Simdf32x4 = self.into(); - s.approx_reciprocal().into() - } -} - -#[cfg(feature = "simd")] -impl Into for Vector4 { - #[inline] - fn into(self) -> Simdf32x4 { - let self_ref: &[f32; 4] = self.as_ref(); - Simdf32x4::load(self_ref.as_ref(), 0 as usize) - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdf32x4]; Add> for Vector4 { - fn add(lhs, rhs) -> Vector4 { - (lhs + rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdf32x4]; Sub> for Vector4 { - fn sub(lhs, rhs) -> Vector4 { - (lhs - rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{@rs - [Simdf32x4]; Mul for Vector4 { - fn mul(lhs, rhs) -> Vector4 { - (lhs * rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{@rs - [Simdf32x4]; Div for Vector4 { - fn div(lhs, rhs) -> Vector4 { - (lhs / rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdf32x4]; Neg for Vector4 { - fn neg(lhs) -> Vector4 { - (-lhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl AddAssign for Vector4 { - #[inline] - fn add_assign(&mut self, rhs: Self) { - let s: Simdf32x4 = (*self).into(); - let rhs: Simdf32x4 = rhs.into(); - *self = (s + rhs).into(); - } -} - -#[cfg(feature = "simd")] -impl SubAssign for Vector4 { - #[inline] - fn sub_assign(&mut self, rhs: Self) { - let s: Simdf32x4 = (*self).into(); - let rhs: Simdf32x4 = rhs.into(); - *self = (s - rhs).into(); - } -} - -#[cfg(feature = "simd")] -impl MulAssign for Vector4 { - fn mul_assign(&mut self, other: f32) { - let s: Simdf32x4 = (*self).into(); - let other = Simdf32x4::splat(other); - *self = (s * other).into(); - } -} - -#[cfg(feature = "simd")] -impl DivAssign for Vector4 { - fn div_assign(&mut self, other: f32) { - let s: Simdf32x4 = (*self).into(); - let other = Simdf32x4::splat(other); - *self = (s / other).into(); - } -} - -#[cfg(feature = "simd")] -impl ElementWise for Vector4 { - #[inline] - fn add_element_wise(self, rhs: Vector4) -> Vector4 { - self + rhs - } - #[inline] - fn sub_element_wise(self, rhs: Vector4) -> Vector4 { - self - rhs - } - #[inline] - fn mul_element_wise(self, rhs: Vector4) -> Vector4 { - let s: Simdf32x4 = self.into(); - let rhs: Simdf32x4 = rhs.into(); - (s * rhs).into() - } - #[inline] - fn div_element_wise(self, rhs: Vector4) -> Vector4 { - let s: Simdf32x4 = self.into(); - let rhs: Simdf32x4 = rhs.into(); - (s / rhs).into() - } - - #[inline] - fn add_assign_element_wise(&mut self, rhs: Vector4) { - (*self) += rhs; - } - - #[inline] - fn sub_assign_element_wise(&mut self, rhs: Vector4) { - (*self) -= rhs; - } - - #[inline] - fn mul_assign_element_wise(&mut self, rhs: Vector4) { - let s: Simdf32x4 = (*self).into(); - let rhs: Simdf32x4 = rhs.into(); - *self = (s * rhs).into(); - } - - #[inline] - fn div_assign_element_wise(&mut self, rhs: Vector4) { - let s: Simdf32x4 = (*self).into(); - let rhs: Simdf32x4 = rhs.into(); - *self = (s * rhs).into(); - } -} - -#[cfg(feature = "simd")] -impl ElementWise for Vector4 { - #[inline] - fn add_element_wise(self, rhs: f32) -> Vector4 { - let s: Simdf32x4 = self.into(); - let rhs = Simdf32x4::splat(rhs); - (s + rhs).into() - } - - #[inline] - fn sub_element_wise(self, rhs: f32) -> Vector4 { - let s: Simdf32x4 = self.into(); - let rhs = Simdf32x4::splat(rhs); - (s - rhs).into() - } - - #[inline] - fn mul_element_wise(self, rhs: f32) -> Vector4 { - self * rhs - } - - #[inline] - fn div_element_wise(self, rhs: f32) -> Vector4 { - self / rhs - } - - #[inline] - fn add_assign_element_wise(&mut self, rhs: f32) { - let s: Simdf32x4 = (*self).into(); - let rhs = Simdf32x4::splat(rhs); - *self = (s + rhs).into(); - } - - #[inline] - fn sub_assign_element_wise(&mut self, rhs: f32) { - let s: Simdf32x4 = (*self).into(); - let rhs = Simdf32x4::splat(rhs); - *self = (s - rhs).into(); - } - - #[inline] - fn mul_assign_element_wise(&mut self, rhs: f32) { - (*self) *= rhs; - } - - #[inline] - fn div_assign_element_wise(&mut self, rhs: f32) { - (*self) /= rhs; - } -} - -#[cfg(feature = "simd")] -impl From for Vector4 { - #[inline] - fn from(f: Simdi32x4) -> Self { - unsafe { - let mut ret: Self = mem::uninitialized(); - { - let ret_mut: &mut [i32; 4] = ret.as_mut(); - f.store(ret_mut.as_mut(), 0 as usize); - } - ret - } - } -} - -#[cfg(feature = "simd")] -impl Into for Vector4 { - #[inline] - fn into(self) -> Simdi32x4 { - let self_ref: &[i32; 4] = self.as_ref(); - Simdi32x4::load(self_ref.as_ref(), 0 as usize) - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdi32x4]; Add> for Vector4 { - fn add(lhs, rhs) -> Vector4 { - (lhs + rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdi32x4]; Sub> for Vector4 { - fn sub(lhs, rhs) -> Vector4 { - (lhs - rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{@rs - [Simdi32x4]; Mul for Vector4 { - fn mul(lhs, rhs) -> Vector4 { - (lhs * rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdi32x4]; Neg for Vector4 { - fn neg(lhs) -> Vector4 { - (-lhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl AddAssign for Vector4 { - #[inline] - fn add_assign(&mut self, rhs: Self) { - let s: Simdi32x4 = (*self).into(); - let rhs: Simdi32x4 = rhs.into(); - *self = (s + rhs).into(); - } -} - -#[cfg(feature = "simd")] -impl SubAssign for Vector4 { - #[inline] - fn sub_assign(&mut self, rhs: Self) { - let s: Simdi32x4 = (*self).into(); - let rhs: Simdi32x4 = rhs.into(); - *self = (s - rhs).into(); - } -} - -#[cfg(feature = "simd")] -impl MulAssign for Vector4 { - fn mul_assign(&mut self, other: i32) { - let s: Simdi32x4 = (*self).into(); - let other = Simdi32x4::splat(other); - *self = (s * other).into(); - } -} - -#[cfg(feature = "simd")] -impl From for Vector4 { - #[inline] - fn from(f: Simdu32x4) -> Self { - unsafe { - let mut ret: Self = mem::uninitialized(); - { - let ret_mut: &mut [u32; 4] = ret.as_mut(); - f.store(ret_mut.as_mut(), 0 as usize); - } - ret - } - } -} - -#[cfg(feature = "simd")] -impl Into for Vector4 { - #[inline] - fn into(self) -> Simdu32x4 { - let self_ref: &[u32; 4] = self.as_ref(); - Simdu32x4::load(self_ref.as_ref(), 0 as usize) - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdu32x4]; Add> for Vector4 { - fn add(lhs, rhs) -> Vector4 { - (lhs + rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdu32x4]; Sub> for Vector4 { - fn sub(lhs, rhs) -> Vector4 { - (lhs - rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{@rs - [Simdu32x4]; Mul for Vector4 { - fn mul(lhs, rhs) -> Vector4 { - (lhs * rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl AddAssign for Vector4 { - #[inline] - fn add_assign(&mut self, rhs: Self) { - let s: Simdu32x4 = (*self).into(); - let rhs: Simdu32x4 = rhs.into(); - *self = (s + rhs).into(); - } -} - -#[cfg(feature = "simd")] -impl SubAssign for Vector4 { - #[inline] - fn sub_assign(&mut self, rhs: Self) { - let s: Simdu32x4 = (*self).into(); - let rhs: Simdu32x4 = rhs.into(); - *self = (s - rhs).into(); - } -} - -#[cfg(feature = "simd")] -impl MulAssign for Vector4 { - fn mul_assign(&mut self, other: u32) { - let s: Simdu32x4 = (*self).into(); - let other = Simdu32x4::splat(other); - *self = (s * other).into(); - } -} - #[cfg(feature = "mint")] impl_mint_conversions!(Vector2 { x, y }, Vector2); #[cfg(feature = "mint")] diff --git a/src/vector_simd.rs b/src/vector_simd.rs new file mode 100644 index 0000000..3c41d1a --- /dev/null +++ b/src/vector_simd.rs @@ -0,0 +1,393 @@ +// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use vector::*; + +use structure::*; + +use std::mem; +use std::ops::*; + +use simd::f32x4 as Simdf32x4; +use simd::i32x4 as Simdi32x4; +use simd::u32x4 as Simdu32x4; + +impl From for Vector4 { + #[inline] + fn from(f: Simdf32x4) -> Self { + unsafe { + let mut ret: Self = mem::uninitialized(); + { + let ret_mut: &mut [f32; 4] = ret.as_mut(); + f.store(ret_mut.as_mut(), 0 as usize); + } + ret + } + } +} + +impl Vector4 { + /// Compute and return the square root of each element. + #[inline] + pub fn sqrt_element_wide(self) -> Self { + let s: Simdf32x4 = self.into(); + s.sqrt().into() + } + + /// Compute and return the reciprocal of the square root of each element. + #[inline] + pub fn rsqrt_element_wide(self) -> Self { + let s: Simdf32x4 = self.into(); + s.approx_rsqrt().into() + } + + /// Compute and return the reciprocal of each element. + #[inline] + pub fn recip_element_wide(self) -> Self { + let s: Simdf32x4 = self.into(); + s.approx_reciprocal().into() + } +} + +impl Into for Vector4 { + #[inline] + fn into(self) -> Simdf32x4 { + let self_ref: &[f32; 4] = self.as_ref(); + Simdf32x4::load(self_ref.as_ref(), 0 as usize) + } +} + +impl_operator_simd!{ + [Simdf32x4]; Add> for Vector4 { + fn add(lhs, rhs) -> Vector4 { + (lhs + rhs).into() + } + } +} + +impl_operator_simd!{ + [Simdf32x4]; Sub> for Vector4 { + fn sub(lhs, rhs) -> Vector4 { + (lhs - rhs).into() + } + } +} + +impl_operator_simd!{@rs + [Simdf32x4]; Mul for Vector4 { + fn mul(lhs, rhs) -> Vector4 { + (lhs * rhs).into() + } + } +} + +impl_operator_simd!{@rs + [Simdf32x4]; Div for Vector4 { + fn div(lhs, rhs) -> Vector4 { + (lhs / rhs).into() + } + } +} + +impl_operator_simd!{ + [Simdf32x4]; Neg for Vector4 { + fn neg(lhs) -> Vector4 { + (-lhs).into() + } + } +} + +impl AddAssign for Vector4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + let s: Simdf32x4 = (*self).into(); + let rhs: Simdf32x4 = rhs.into(); + *self = (s + rhs).into(); + } +} + +impl SubAssign for Vector4 { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + let s: Simdf32x4 = (*self).into(); + let rhs: Simdf32x4 = rhs.into(); + *self = (s - rhs).into(); + } +} + +impl MulAssign for Vector4 { + fn mul_assign(&mut self, other: f32) { + let s: Simdf32x4 = (*self).into(); + let other = Simdf32x4::splat(other); + *self = (s * other).into(); + } +} + +impl DivAssign for Vector4 { + fn div_assign(&mut self, other: f32) { + let s: Simdf32x4 = (*self).into(); + let other = Simdf32x4::splat(other); + *self = (s / other).into(); + } +} + +impl ElementWise for Vector4 { + #[inline] + fn add_element_wise(self, rhs: Vector4) -> Vector4 { + self + rhs + } + #[inline] + fn sub_element_wise(self, rhs: Vector4) -> Vector4 { + self - rhs + } + #[inline] + fn mul_element_wise(self, rhs: Vector4) -> Vector4 { + let s: Simdf32x4 = self.into(); + let rhs: Simdf32x4 = rhs.into(); + (s * rhs).into() + } + #[inline] + fn div_element_wise(self, rhs: Vector4) -> Vector4 { + let s: Simdf32x4 = self.into(); + let rhs: Simdf32x4 = rhs.into(); + (s / rhs).into() + } + + #[inline] + fn add_assign_element_wise(&mut self, rhs: Vector4) { + (*self) += rhs; + } + + #[inline] + fn sub_assign_element_wise(&mut self, rhs: Vector4) { + (*self) -= rhs; + } + + #[inline] + fn mul_assign_element_wise(&mut self, rhs: Vector4) { + let s: Simdf32x4 = (*self).into(); + let rhs: Simdf32x4 = rhs.into(); + *self = (s * rhs).into(); + } + + #[inline] + fn div_assign_element_wise(&mut self, rhs: Vector4) { + let s: Simdf32x4 = (*self).into(); + let rhs: Simdf32x4 = rhs.into(); + *self = (s * rhs).into(); + } +} + +impl ElementWise for Vector4 { + #[inline] + fn add_element_wise(self, rhs: f32) -> Vector4 { + let s: Simdf32x4 = self.into(); + let rhs = Simdf32x4::splat(rhs); + (s + rhs).into() + } + + #[inline] + fn sub_element_wise(self, rhs: f32) -> Vector4 { + let s: Simdf32x4 = self.into(); + let rhs = Simdf32x4::splat(rhs); + (s - rhs).into() + } + + #[inline] + fn mul_element_wise(self, rhs: f32) -> Vector4 { + self * rhs + } + + #[inline] + fn div_element_wise(self, rhs: f32) -> Vector4 { + self / rhs + } + + #[inline] + fn add_assign_element_wise(&mut self, rhs: f32) { + let s: Simdf32x4 = (*self).into(); + let rhs = Simdf32x4::splat(rhs); + *self = (s + rhs).into(); + } + + #[inline] + fn sub_assign_element_wise(&mut self, rhs: f32) { + let s: Simdf32x4 = (*self).into(); + let rhs = Simdf32x4::splat(rhs); + *self = (s - rhs).into(); + } + + #[inline] + fn mul_assign_element_wise(&mut self, rhs: f32) { + (*self) *= rhs; + } + + #[inline] + fn div_assign_element_wise(&mut self, rhs: f32) { + (*self) /= rhs; + } +} + +impl From for Vector4 { + #[inline] + fn from(f: Simdi32x4) -> Self { + unsafe { + let mut ret: Self = mem::uninitialized(); + { + let ret_mut: &mut [i32; 4] = ret.as_mut(); + f.store(ret_mut.as_mut(), 0 as usize); + } + ret + } + } +} + +impl Into for Vector4 { + #[inline] + fn into(self) -> Simdi32x4 { + let self_ref: &[i32; 4] = self.as_ref(); + Simdi32x4::load(self_ref.as_ref(), 0 as usize) + } +} + +impl_operator_simd!{ + [Simdi32x4]; Add> for Vector4 { + fn add(lhs, rhs) -> Vector4 { + (lhs + rhs).into() + } + } +} + +impl_operator_simd!{ + [Simdi32x4]; Sub> for Vector4 { + fn sub(lhs, rhs) -> Vector4 { + (lhs - rhs).into() + } + } +} + +impl_operator_simd!{@rs + [Simdi32x4]; Mul for Vector4 { + fn mul(lhs, rhs) -> Vector4 { + (lhs * rhs).into() + } + } +} + +impl_operator_simd!{ + [Simdi32x4]; Neg for Vector4 { + fn neg(lhs) -> Vector4 { + (-lhs).into() + } + } +} + +impl AddAssign for Vector4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + let s: Simdi32x4 = (*self).into(); + let rhs: Simdi32x4 = rhs.into(); + *self = (s + rhs).into(); + } +} + +impl SubAssign for Vector4 { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + let s: Simdi32x4 = (*self).into(); + let rhs: Simdi32x4 = rhs.into(); + *self = (s - rhs).into(); + } +} + +impl MulAssign for Vector4 { + fn mul_assign(&mut self, other: i32) { + let s: Simdi32x4 = (*self).into(); + let other = Simdi32x4::splat(other); + *self = (s * other).into(); + } +} + +impl From for Vector4 { + #[inline] + fn from(f: Simdu32x4) -> Self { + unsafe { + let mut ret: Self = mem::uninitialized(); + { + let ret_mut: &mut [u32; 4] = ret.as_mut(); + f.store(ret_mut.as_mut(), 0 as usize); + } + ret + } + } +} + +impl Into for Vector4 { + #[inline] + fn into(self) -> Simdu32x4 { + let self_ref: &[u32; 4] = self.as_ref(); + Simdu32x4::load(self_ref.as_ref(), 0 as usize) + } +} + +impl_operator_simd!{ + [Simdu32x4]; Add> for Vector4 { + fn add(lhs, rhs) -> Vector4 { + (lhs + rhs).into() + } + } +} + +impl_operator_simd!{ + [Simdu32x4]; Sub> for Vector4 { + fn sub(lhs, rhs) -> Vector4 { + (lhs - rhs).into() + } + } +} + +impl_operator_simd!{@rs + [Simdu32x4]; Mul for Vector4 { + fn mul(lhs, rhs) -> Vector4 { + (lhs * rhs).into() + } + } +} + +impl AddAssign for Vector4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + let s: Simdu32x4 = (*self).into(); + let rhs: Simdu32x4 = rhs.into(); + *self = (s + rhs).into(); + } +} + +impl SubAssign for Vector4 { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + let s: Simdu32x4 = (*self).into(); + let rhs: Simdu32x4 = rhs.into(); + *self = (s - rhs).into(); + } +} + +impl MulAssign for Vector4 { + fn mul_assign(&mut self, other: u32) { + let s: Simdu32x4 = (*self).into(); + let other = Simdu32x4::splat(other); + *self = (s * other).into(); + } +} diff --git a/tests/matrix.rs b/tests/matrix.rs index f516d4b..236a2f1 100644 --- a/tests/matrix.rs +++ b/tests/matrix.rs @@ -281,7 +281,7 @@ pub mod matrix3 { } #[test] - fn test_determinant() {; + fn test_determinant() { assert_eq!(A.determinant(), 0.0f64); }