1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud (at) inria.fr> 5 // 6 // This Source Code Form is subject to the terms of the Mozilla 7 // Public License v. 2.0. If a copy of the MPL was not distributed 8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 10 #ifndef EIGEN_ASSIGNMENT_FUNCTORS_H 11 #define EIGEN_ASSIGNMENT_FUNCTORS_H 12 13 namespace Eigen { 14 15 namespace internal { 16 17 /** \internal 18 * \brief Template functor for scalar/packet assignment 19 * 20 */ 21 template<typename DstScalar,typename SrcScalar> struct assign_op { 22 23 EIGEN_EMPTY_STRUCT_CTOR(assign_op) 24 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(DstScalar& a, const SrcScalar& b) const { a = b; } 25 26 template<int Alignment, typename Packet> 27 EIGEN_STRONG_INLINE void assignPacket(DstScalar* a, const Packet& b) const 28 { internal::pstoret<DstScalar,Packet,Alignment>(a,b); } 29 }; 30 31 // Empty overload for void type (used by PermutationMatrix) 32 template<typename DstScalar> struct assign_op<DstScalar,void> {}; 33 34 template<typename DstScalar,typename SrcScalar> 35 struct functor_traits<assign_op<DstScalar,SrcScalar> > { 36 enum { 37 Cost = NumTraits<DstScalar>::ReadCost, 38 PacketAccess = is_same<DstScalar,SrcScalar>::value && packet_traits<DstScalar>::Vectorizable && packet_traits<SrcScalar>::Vectorizable 39 }; 40 }; 41 42 /** \internal 43 * \brief Template functor for scalar/packet assignment with addition 44 * 45 */ 46 template<typename DstScalar,typename SrcScalar> struct add_assign_op { 47 48 EIGEN_EMPTY_STRUCT_CTOR(add_assign_op) 49 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(DstScalar& a, const SrcScalar& b) const { a += b; } 50 51 template<int Alignment, typename Packet> 52 EIGEN_STRONG_INLINE void assignPacket(DstScalar* a, const Packet& b) const 53 { internal::pstoret<DstScalar,Packet,Alignment>(a,internal::padd(internal::ploadt<Packet,Alignment>(a),b)); } 54 }; 55 template<typename DstScalar,typename SrcScalar> 56 struct functor_traits<add_assign_op<DstScalar,SrcScalar> > { 57 enum { 58 Cost = NumTraits<DstScalar>::ReadCost + NumTraits<DstScalar>::AddCost, 59 PacketAccess = is_same<DstScalar,SrcScalar>::value && packet_traits<DstScalar>::HasAdd 60 }; 61 }; 62 63 /** \internal 64 * \brief Template functor for scalar/packet assignment with subtraction 65 * 66 */ 67 template<typename DstScalar,typename SrcScalar> struct sub_assign_op { 68 69 EIGEN_EMPTY_STRUCT_CTOR(sub_assign_op) 70 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(DstScalar& a, const SrcScalar& b) const { a -= b; } 71 72 template<int Alignment, typename Packet> 73 EIGEN_STRONG_INLINE void assignPacket(DstScalar* a, const Packet& b) const 74 { internal::pstoret<DstScalar,Packet,Alignment>(a,internal::psub(internal::ploadt<Packet,Alignment>(a),b)); } 75 }; 76 template<typename DstScalar,typename SrcScalar> 77 struct functor_traits<sub_assign_op<DstScalar,SrcScalar> > { 78 enum { 79 Cost = NumTraits<DstScalar>::ReadCost + NumTraits<DstScalar>::AddCost, 80 PacketAccess = is_same<DstScalar,SrcScalar>::value && packet_traits<DstScalar>::HasSub 81 }; 82 }; 83 84 /** \internal 85 * \brief Template functor for scalar/packet assignment with multiplication 86 * 87 */ 88 template<typename DstScalar, typename SrcScalar=DstScalar> 89 struct mul_assign_op { 90 91 EIGEN_EMPTY_STRUCT_CTOR(mul_assign_op) 92 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(DstScalar& a, const SrcScalar& b) const { a *= b; } 93 94 template<int Alignment, typename Packet> 95 EIGEN_STRONG_INLINE void assignPacket(DstScalar* a, const Packet& b) const 96 { internal::pstoret<DstScalar,Packet,Alignment>(a,internal::pmul(internal::ploadt<Packet,Alignment>(a),b)); } 97 }; 98 template<typename DstScalar, typename SrcScalar> 99 struct functor_traits<mul_assign_op<DstScalar,SrcScalar> > { 100 enum { 101 Cost = NumTraits<DstScalar>::ReadCost + NumTraits<DstScalar>::MulCost, 102 PacketAccess = is_same<DstScalar,SrcScalar>::value && packet_traits<DstScalar>::HasMul 103 }; 104 }; 105 106 /** \internal 107 * \brief Template functor for scalar/packet assignment with diviving 108 * 109 */ 110 template<typename DstScalar, typename SrcScalar=DstScalar> struct div_assign_op { 111 112 EIGEN_EMPTY_STRUCT_CTOR(div_assign_op) 113 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(DstScalar& a, const SrcScalar& b) const { a /= b; } 114 115 template<int Alignment, typename Packet> 116 EIGEN_STRONG_INLINE void assignPacket(DstScalar* a, const Packet& b) const 117 { internal::pstoret<DstScalar,Packet,Alignment>(a,internal::pdiv(internal::ploadt<Packet,Alignment>(a),b)); } 118 }; 119 template<typename DstScalar, typename SrcScalar> 120 struct functor_traits<div_assign_op<DstScalar,SrcScalar> > { 121 enum { 122 Cost = NumTraits<DstScalar>::ReadCost + NumTraits<DstScalar>::MulCost, 123 PacketAccess = is_same<DstScalar,SrcScalar>::value && packet_traits<DstScalar>::HasDiv 124 }; 125 }; 126 127 /** \internal 128 * \brief Template functor for scalar/packet assignment with swapping 129 * 130 * It works as follow. For a non-vectorized evaluation loop, we have: 131 * for(i) func(A.coeffRef(i), B.coeff(i)); 132 * where B is a SwapWrapper expression. The trick is to make SwapWrapper::coeff behaves like a non-const coeffRef. 133 * Actually, SwapWrapper might not even be needed since even if B is a plain expression, since it has to be writable 134 * B.coeff already returns a const reference to the underlying scalar value. 135 * 136 * The case of a vectorized loop is more tricky: 137 * for(i,j) func.assignPacket<A_Align>(&A.coeffRef(i,j), B.packet<B_Align>(i,j)); 138 * Here, B must be a SwapWrapper whose packet function actually returns a proxy object holding a Scalar*, 139 * the actual alignment and Packet type. 140 * 141 */ 142 template<typename Scalar> struct swap_assign_op { 143 144 EIGEN_EMPTY_STRUCT_CTOR(swap_assign_op) 145 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Scalar& a, const Scalar& b) const 146 { 147 #ifdef __CUDACC__ 148 // FIXME is there some kind of cuda::swap? 149 Scalar t=b; const_cast<Scalar&>(b)=a; a=t; 150 #else 151 using std::swap; 152 swap(a,const_cast<Scalar&>(b)); 153 #endif 154 } 155 }; 156 template<typename Scalar> 157 struct functor_traits<swap_assign_op<Scalar> > { 158 enum { 159 Cost = 3 * NumTraits<Scalar>::ReadCost, 160 PacketAccess = packet_traits<Scalar>::Vectorizable 161 }; 162 }; 163 164 } // namespace internal 165 166 } // namespace Eigen 167 168 #endif // EIGEN_ASSIGNMENT_FUNCTORS_H 169