// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Rohit Garg // Copyright (C) 2009-2010 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_GEOMETRY_SIMD_H #define EIGEN_GEOMETRY_SIMD_H namespace Eigen { namespace internal { template struct quat_product { enum { AAlignment = traits::Alignment, BAlignment = traits::Alignment, ResAlignment = traits >::Alignment }; static inline Quaternion run(const QuaternionBase& _a, const QuaternionBase& _b) { evaluator ae(_a.coeffs()); evaluator be(_b.coeffs()); Quaternion res; float arr[4] = {0.f, 0.f, 0.f, -0.f}; const Packet4f mask = pset(arr); Packet4f a = ae.template packet(0); Packet4f b = be.template packet(0); Packet4f s1 = pmul(vec4f_swizzle1(a,1,2,0,2),vec4f_swizzle1(b,2,0,1,2)); Packet4f s2 = pmul(vec4f_swizzle1(a,3,3,3,1),vec4f_swizzle1(b,0,1,2,1)); pstoret( &res.x(), padd(psub(pmul(a,vec4f_swizzle1(b,3,3,3,3)), pmul(vec4f_swizzle1(a,2,0,1,0), vec4f_swizzle1(b,1,2,0,0))), pxor(mask,padd(s1,s2)))); return res; } }; template struct quat_conj { enum { ResAlignment = traits >::Alignment }; static inline Quaternion run(const QuaternionBase& q) { evaluator qe(q.coeffs()); Quaternion res; float arr[4] = {-0.f,-0.f,-0.f,0.f}; const Packet4f mask = pset(arr); pstoret(&res.x(), pxor(mask, qe.template packet::Alignment,Packet4f>(0))); return res; } }; template struct cross3_impl { enum { ResAlignment = traits::type>::Alignment }; static inline typename plain_matrix_type::type run(const VectorLhs& lhs, const VectorRhs& rhs) { evaluator lhs_eval(lhs); evaluator rhs_eval(rhs); Packet4f a = lhs_eval.template packet::Alignment,Packet4f>(0); Packet4f b = rhs_eval.template packet::Alignment,Packet4f>(0); Packet4f mul1 = pmul(vec4f_swizzle1(a,1,2,0,3),vec4f_swizzle1(b,2,0,1,3)); Packet4f mul2 = pmul(vec4f_swizzle1(a,2,0,1,3),vec4f_swizzle1(b,1,2,0,3)); typename plain_matrix_type::type res; pstoret(&res.x(),psub(mul1,mul2)); return res; } }; #if (defined EIGEN_VECTORIZE_SSE) || (EIGEN_ARCH_ARM64) template struct quat_product { enum { BAlignment = traits::Alignment, ResAlignment = traits >::Alignment }; static inline Quaternion run(const QuaternionBase& _a, const QuaternionBase& _b) { Quaternion res; evaluator ae(_a.coeffs()); evaluator be(_b.coeffs()); const double* a = _a.coeffs().data(); Packet2d b_xy = be.template packet(0); Packet2d b_zw = be.template packet(2); Packet2d a_xx = pset1(a[0]); Packet2d a_yy = pset1(a[1]); Packet2d a_zz = pset1(a[2]); Packet2d a_ww = pset1(a[3]); // two temporaries: Packet2d t1, t2; /* * t1 = ww*xy + yy*zw * t2 = zz*xy - xx*zw * res.xy = t1 +/- swap(t2) */ t1 = padd(pmul(a_ww, b_xy), pmul(a_yy, b_zw)); t2 = psub(pmul(a_zz, b_xy), pmul(a_xx, b_zw)); pstoret(&res.x(), paddsub(t1, preverse(t2))); /* * t1 = ww*zw - yy*xy * t2 = zz*zw + xx*xy * res.zw = t1 -/+ swap(t2) = swap( swap(t1) +/- t2) */ t1 = psub(pmul(a_ww, b_zw), pmul(a_yy, b_xy)); t2 = padd(pmul(a_zz, b_zw), pmul(a_xx, b_xy)); pstoret(&res.z(), preverse(paddsub(preverse(t1), t2))); return res; } }; template struct quat_conj { enum { ResAlignment = traits >::Alignment }; static inline Quaternion run(const QuaternionBase& q) { evaluator qe(q.coeffs()); Quaternion res; const double neg_zero = numext::bit_cast(0x8000000000000000ull); double arr1[2] = {neg_zero, neg_zero}; double arr2[2] = {neg_zero, 0.0}; const Packet2d mask0 = pset(arr1); const Packet2d mask2 = pset(arr2); pstoret(&res.x(), pxor(mask0, qe.template packet::Alignment,Packet2d>(0))); pstoret(&res.z(), pxor(mask2, qe.template packet::Alignment,Packet2d>(2))); return res; } }; #endif // end EIGEN_VECTORIZE_SSE_OR_EIGEN_ARCH_ARM64 } // end namespace internal } // end namespace Eigen #endif // EIGEN_GEOMETRY_SIMD_H