xref: /aosp_15_r20/external/eigen/Eigen/src/Core/functors/AssignmentFunctors.h (revision bf2c37156dfe67e5dfebd6d394bad8b2ab5804d4)
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008-2010 Gael Guennebaud <[email protected]>
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 
EIGEN_EMPTY_STRUCT_CTORassign_op23   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>
assignPacketassign_op27   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 EIGEN_GPUCC
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 =
161     #if defined(EIGEN_VECTORIZE_AVX) && EIGEN_COMP_CLANG && (EIGEN_COMP_CLANG<800 || defined(__apple_build_version__))
162     // This is a partial workaround for a bug in clang generating bad code
163     // when mixing 256/512 bits loads and 128 bits moves.
164     // See http://eigen.tuxfamily.org/bz/show_bug.cgi?id=1684
165     //     https://bugs.llvm.org/show_bug.cgi?id=40815
166     0
167     #else
168     packet_traits<Scalar>::Vectorizable
169     #endif
170   };
171 };
172 
173 } // namespace internal
174 
175 } // namespace Eigen
176 
177 #endif // EIGEN_ASSIGNMENT_FUNCTORS_H
178