Merge of itasc branch. Project files, scons and cmake should be working. Makefile...
[blender.git] / extern / Eigen2 / Eigen / src / Core / arch / SSE / PacketMath.h
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra. Eigen itself is part of the KDE project.
3 //
4 // Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
5 //
6 // Eigen is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 3 of the License, or (at your option) any later version.
10 //
11 // Alternatively, you can redistribute it and/or
12 // modify it under the terms of the GNU General Public License as
13 // published by the Free Software Foundation; either version 2 of
14 // the License, or (at your option) any later version.
15 //
16 // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License and a copy of the GNU General Public License along with
23 // Eigen. If not, see <http://www.gnu.org/licenses/>.
24
25 #ifndef EIGEN_PACKET_MATH_SSE_H
26 #define EIGEN_PACKET_MATH_SSE_H
27
28 #ifndef EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD
29 #define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 16
30 #endif
31
32 template<> struct ei_packet_traits<float>  { typedef __m128  type; enum {size=4}; };
33 template<> struct ei_packet_traits<double> { typedef __m128d type; enum {size=2}; };
34 template<> struct ei_packet_traits<int>    { typedef __m128i type; enum {size=4}; };
35
36 template<> struct ei_unpacket_traits<__m128>  { typedef float  type; enum {size=4}; };
37 template<> struct ei_unpacket_traits<__m128d> { typedef double type; enum {size=2}; };
38 template<> struct ei_unpacket_traits<__m128i> { typedef int    type; enum {size=4}; };
39
40 template<> EIGEN_STRONG_INLINE __m128  ei_pset1<float>(const float&  from) { return _mm_set1_ps(from); }
41 template<> EIGEN_STRONG_INLINE __m128d ei_pset1<double>(const double& from) { return _mm_set1_pd(from); }
42 template<> EIGEN_STRONG_INLINE __m128i ei_pset1<int>(const int&    from) { return _mm_set1_epi32(from); }
43
44 template<> EIGEN_STRONG_INLINE __m128  ei_padd<__m128>(const __m128&  a, const __m128&  b) { return _mm_add_ps(a,b); }
45 template<> EIGEN_STRONG_INLINE __m128d ei_padd<__m128d>(const __m128d& a, const __m128d& b) { return _mm_add_pd(a,b); }
46 template<> EIGEN_STRONG_INLINE __m128i ei_padd<__m128i>(const __m128i& a, const __m128i& b) { return _mm_add_epi32(a,b); }
47
48 template<> EIGEN_STRONG_INLINE __m128  ei_psub<__m128>(const __m128&  a, const __m128&  b) { return _mm_sub_ps(a,b); }
49 template<> EIGEN_STRONG_INLINE __m128d ei_psub<__m128d>(const __m128d& a, const __m128d& b) { return _mm_sub_pd(a,b); }
50 template<> EIGEN_STRONG_INLINE __m128i ei_psub<__m128i>(const __m128i& a, const __m128i& b) { return _mm_sub_epi32(a,b); }
51
52 template<> EIGEN_STRONG_INLINE __m128  ei_pmul<__m128>(const __m128&  a, const __m128&  b) { return _mm_mul_ps(a,b); }
53 template<> EIGEN_STRONG_INLINE __m128d ei_pmul<__m128d>(const __m128d& a, const __m128d& b) { return _mm_mul_pd(a,b); }
54 template<> EIGEN_STRONG_INLINE __m128i ei_pmul<__m128i>(const __m128i& a, const __m128i& b)
55 {
56   return _mm_or_si128(
57     _mm_and_si128(
58       _mm_mul_epu32(a,b),
59       _mm_setr_epi32(0xffffffff,0,0xffffffff,0)),
60     _mm_slli_si128(
61       _mm_and_si128(
62         _mm_mul_epu32(_mm_srli_si128(a,4),_mm_srli_si128(b,4)),
63         _mm_setr_epi32(0xffffffff,0,0xffffffff,0)), 4));
64 }
65
66 template<> EIGEN_STRONG_INLINE __m128  ei_pdiv<__m128>(const __m128&  a, const __m128&  b) { return _mm_div_ps(a,b); }
67 template<> EIGEN_STRONG_INLINE __m128d ei_pdiv<__m128d>(const __m128d& a, const __m128d& b) { return _mm_div_pd(a,b); }
68 template<> EIGEN_STRONG_INLINE __m128i ei_pdiv<__m128i>(const __m128i& /*a*/, const __m128i& /*b*/)
69 { ei_assert(false && "packet integer division are not supported by SSE");
70   __m128i dummy = ei_pset1<int>(0);
71   return dummy;
72 }
73
74 // for some weird raisons, it has to be overloaded for packet integer
75 template<> EIGEN_STRONG_INLINE __m128i ei_pmadd(const __m128i& a, const __m128i& b, const __m128i& c) { return ei_padd(ei_pmul(a,b), c); }
76
77 template<> EIGEN_STRONG_INLINE __m128  ei_pmin<__m128>(const __m128&  a, const __m128&  b) { return _mm_min_ps(a,b); }
78 template<> EIGEN_STRONG_INLINE __m128d ei_pmin<__m128d>(const __m128d& a, const __m128d& b) { return _mm_min_pd(a,b); }
79 // FIXME this vectorized min operator is likely to be slower than the standard one
80 template<> EIGEN_STRONG_INLINE __m128i ei_pmin<__m128i>(const __m128i& a, const __m128i& b)
81 {
82   __m128i mask = _mm_cmplt_epi32(a,b);
83   return _mm_or_si128(_mm_and_si128(mask,a),_mm_andnot_si128(mask,b));
84 }
85
86 template<> EIGEN_STRONG_INLINE __m128  ei_pmax<__m128>(const __m128&  a, const __m128&  b) { return _mm_max_ps(a,b); }
87 template<> EIGEN_STRONG_INLINE __m128d ei_pmax<__m128d>(const __m128d& a, const __m128d& b) { return _mm_max_pd(a,b); }
88 // FIXME this vectorized max operator is likely to be slower than the standard one
89 template<> EIGEN_STRONG_INLINE __m128i ei_pmax<__m128i>(const __m128i& a, const __m128i& b)
90 {
91   __m128i mask = _mm_cmpgt_epi32(a,b);
92   return _mm_or_si128(_mm_and_si128(mask,a),_mm_andnot_si128(mask,b));
93 }
94
95 template<> EIGEN_STRONG_INLINE __m128  ei_pload<float>(const float*   from) { return _mm_load_ps(from); }
96 template<> EIGEN_STRONG_INLINE __m128d ei_pload<double>(const double*  from) { return _mm_load_pd(from); }
97 template<> EIGEN_STRONG_INLINE __m128i ei_pload<int>(const int* from) { return _mm_load_si128(reinterpret_cast<const __m128i*>(from)); }
98
99 template<> EIGEN_STRONG_INLINE __m128  ei_ploadu<float>(const float*   from) { return _mm_loadu_ps(from); }
100 // template<> EIGEN_STRONG_INLINE __m128  ei_ploadu(const float*   from) {
101 //   if (size_t(from)&0xF)
102 //     return _mm_loadu_ps(from);
103 //   else 
104 //     return _mm_loadu_ps(from);
105 // }
106 template<> EIGEN_STRONG_INLINE __m128d ei_ploadu<double>(const double*  from) { return _mm_loadu_pd(from); }
107 template<> EIGEN_STRONG_INLINE __m128i ei_ploadu<int>(const int* from) { return _mm_loadu_si128(reinterpret_cast<const __m128i*>(from)); }
108
109 template<> EIGEN_STRONG_INLINE void ei_pstore<float>(float*  to, const __m128&  from) { _mm_store_ps(to, from); }
110 template<> EIGEN_STRONG_INLINE void ei_pstore<double>(double* to, const __m128d& from) { _mm_store_pd(to, from); }
111 template<> EIGEN_STRONG_INLINE void ei_pstore<int>(int*    to, const __m128i& from) { _mm_store_si128(reinterpret_cast<__m128i*>(to), from); }
112
113 template<> EIGEN_STRONG_INLINE void ei_pstoreu<float>(float*  to, const __m128&  from) { _mm_storeu_ps(to, from); }
114 template<> EIGEN_STRONG_INLINE void ei_pstoreu<double>(double* to, const __m128d& from) { _mm_storeu_pd(to, from); }
115 template<> EIGEN_STRONG_INLINE void ei_pstoreu<int>(int*    to, const __m128i& from) { _mm_storeu_si128(reinterpret_cast<__m128i*>(to), from); }
116
117 #ifdef _MSC_VER
118 // this fix internal compilation error
119 template<> EIGEN_STRONG_INLINE float  ei_pfirst<__m128>(const __m128&  a) { float x = _mm_cvtss_f32(a); return x; }
120 template<> EIGEN_STRONG_INLINE double ei_pfirst<__m128d>(const __m128d& a) { double x = _mm_cvtsd_f64(a); return x; }
121 template<> EIGEN_STRONG_INLINE int    ei_pfirst<__m128i>(const __m128i& a) { int x = _mm_cvtsi128_si32(a); return x; }
122 #else
123 template<> EIGEN_STRONG_INLINE float  ei_pfirst<__m128>(const __m128&  a) { return _mm_cvtss_f32(a); }
124 template<> EIGEN_STRONG_INLINE double ei_pfirst<__m128d>(const __m128d& a) { return _mm_cvtsd_f64(a); }
125 template<> EIGEN_STRONG_INLINE int    ei_pfirst<__m128i>(const __m128i& a) { return _mm_cvtsi128_si32(a); }
126 #endif
127
128 #ifdef __SSE3__
129 // TODO implement SSE2 versions as well as integer versions
130 template<> EIGEN_STRONG_INLINE __m128 ei_preduxp<__m128>(const __m128* vecs)
131 {
132   return _mm_hadd_ps(_mm_hadd_ps(vecs[0], vecs[1]),_mm_hadd_ps(vecs[2], vecs[3]));
133 }
134 template<> EIGEN_STRONG_INLINE __m128d ei_preduxp<__m128d>(const __m128d* vecs)
135 {
136   return _mm_hadd_pd(vecs[0], vecs[1]);
137 }
138 // SSSE3 version:
139 // EIGEN_STRONG_INLINE __m128i ei_preduxp(const __m128i* vecs)
140 // {
141 //   return _mm_hadd_epi32(_mm_hadd_epi32(vecs[0], vecs[1]),_mm_hadd_epi32(vecs[2], vecs[3]));
142 // }
143
144 template<> EIGEN_STRONG_INLINE float ei_predux<__m128>(const __m128& a)
145 {
146   __m128 tmp0 = _mm_hadd_ps(a,a);
147   return ei_pfirst(_mm_hadd_ps(tmp0, tmp0));
148 }
149
150 template<> EIGEN_STRONG_INLINE double ei_predux<__m128d>(const __m128d& a) { return ei_pfirst(_mm_hadd_pd(a, a)); }
151
152 // SSSE3 version:
153 // EIGEN_STRONG_INLINE float ei_predux(const __m128i& a)
154 // {
155 //   __m128i tmp0 = _mm_hadd_epi32(a,a);
156 //   return ei_pfirst(_mm_hadd_epi32(tmp0, tmp0));
157 // }
158 #else
159 // SSE2 versions
160 template<> EIGEN_STRONG_INLINE float ei_predux<__m128>(const __m128& a)
161 {
162   __m128 tmp = _mm_add_ps(a, _mm_movehl_ps(a,a));
163   return ei_pfirst(_mm_add_ss(tmp, _mm_shuffle_ps(tmp,tmp, 1)));
164 }
165 template<> EIGEN_STRONG_INLINE double ei_predux<__m128d>(const __m128d& a)
166 {
167   return ei_pfirst(_mm_add_sd(a, _mm_unpackhi_pd(a,a)));
168 }
169
170 template<> EIGEN_STRONG_INLINE __m128 ei_preduxp<__m128>(const __m128* vecs)
171 {
172   __m128 tmp0, tmp1, tmp2;
173   tmp0 = _mm_unpacklo_ps(vecs[0], vecs[1]);
174   tmp1 = _mm_unpackhi_ps(vecs[0], vecs[1]);
175   tmp2 = _mm_unpackhi_ps(vecs[2], vecs[3]);
176   tmp0 = _mm_add_ps(tmp0, tmp1);
177   tmp1 = _mm_unpacklo_ps(vecs[2], vecs[3]);
178   tmp1 = _mm_add_ps(tmp1, tmp2);
179   tmp2 = _mm_movehl_ps(tmp1, tmp0);
180   tmp0 = _mm_movelh_ps(tmp0, tmp1);
181   return _mm_add_ps(tmp0, tmp2);
182 }
183
184 template<> EIGEN_STRONG_INLINE __m128d ei_preduxp<__m128d>(const __m128d* vecs)
185 {
186   return _mm_add_pd(_mm_unpacklo_pd(vecs[0], vecs[1]), _mm_unpackhi_pd(vecs[0], vecs[1]));
187 }
188 #endif  // SSE3
189
190 template<> EIGEN_STRONG_INLINE int ei_predux<__m128i>(const __m128i& a)
191 {
192   __m128i tmp = _mm_add_epi32(a, _mm_unpackhi_epi64(a,a));
193   return ei_pfirst(tmp) + ei_pfirst(_mm_shuffle_epi32(tmp, 1));
194 }
195
196 template<> EIGEN_STRONG_INLINE __m128i ei_preduxp<__m128i>(const __m128i* vecs)
197 {
198   __m128i tmp0, tmp1, tmp2;
199   tmp0 = _mm_unpacklo_epi32(vecs[0], vecs[1]);
200   tmp1 = _mm_unpackhi_epi32(vecs[0], vecs[1]);
201   tmp2 = _mm_unpackhi_epi32(vecs[2], vecs[3]);
202   tmp0 = _mm_add_epi32(tmp0, tmp1);
203   tmp1 = _mm_unpacklo_epi32(vecs[2], vecs[3]);
204   tmp1 = _mm_add_epi32(tmp1, tmp2);
205   tmp2 = _mm_unpacklo_epi64(tmp0, tmp1);
206   tmp0 = _mm_unpackhi_epi64(tmp0, tmp1);
207   return _mm_add_epi32(tmp0, tmp2);
208 }
209
210 #if (defined __GNUC__)
211 // template <> EIGEN_STRONG_INLINE __m128 ei_pmadd(const __m128&  a, const __m128&  b, const __m128&  c)
212 // {
213 //   __m128 res = b;
214 //   asm("mulps %[a], %[b] \n\taddps %[c], %[b]" : [b] "+x" (res) : [a] "x" (a), [c] "x" (c));
215 //   return res;
216 // }
217 // EIGEN_STRONG_INLINE __m128i _mm_alignr_epi8(const __m128i&  a, const __m128i&  b, const int i)
218 // {
219 //   __m128i res = a;
220 //   asm("palignr %[i], %[a], %[b] " : [b] "+x" (res) : [a] "x" (a), [i] "i" (i));
221 //   return res;
222 // }
223 #endif
224
225 #ifdef __SSSE3__
226 // SSSE3 versions
227 template<int Offset>
228 struct ei_palign_impl<Offset,__m128>
229 {
230   EIGEN_STRONG_INLINE static void run(__m128& first, const __m128& second)
231   {
232     if (Offset!=0)
233       first = _mm_castsi128_ps(_mm_alignr_epi8(_mm_castps_si128(second), _mm_castps_si128(first), Offset*4));
234   }
235 };
236
237 template<int Offset>
238 struct ei_palign_impl<Offset,__m128i>
239 {
240   EIGEN_STRONG_INLINE static void run(__m128i& first, const __m128i& second)
241   {
242     if (Offset!=0)
243       first = _mm_alignr_epi8(second,first, Offset*4);
244   }
245 };
246
247 template<int Offset>
248 struct ei_palign_impl<Offset,__m128d>
249 {
250   EIGEN_STRONG_INLINE static void run(__m128d& first, const __m128d& second)
251   {
252     if (Offset==1)
253       first = _mm_castsi128_pd(_mm_alignr_epi8(_mm_castpd_si128(second), _mm_castpd_si128(first), 8));
254   }
255 };
256 #else
257 // SSE2 versions
258 template<int Offset>
259 struct ei_palign_impl<Offset,__m128>
260 {
261   EIGEN_STRONG_INLINE static void run(__m128& first, const __m128& second)
262   {
263     if (Offset==1)
264     {
265       first = _mm_move_ss(first,second);
266       first = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(first),0x39));
267     }
268     else if (Offset==2)
269     {
270       first = _mm_movehl_ps(first,first);
271       first = _mm_movelh_ps(first,second);
272     }
273     else if (Offset==3)
274     {
275       first = _mm_move_ss(first,second);
276       first = _mm_shuffle_ps(first,second,0x93);
277     }
278   }
279 };
280
281 template<int Offset>
282 struct ei_palign_impl<Offset,__m128i>
283 {
284   EIGEN_STRONG_INLINE static void run(__m128i& first, const __m128i& second)
285   {
286     if (Offset==1)
287     {
288       first = _mm_castps_si128(_mm_move_ss(_mm_castsi128_ps(first),_mm_castsi128_ps(second)));
289       first = _mm_shuffle_epi32(first,0x39);
290     }
291     else if (Offset==2)
292     {
293       first = _mm_castps_si128(_mm_movehl_ps(_mm_castsi128_ps(first),_mm_castsi128_ps(first)));
294       first = _mm_castps_si128(_mm_movelh_ps(_mm_castsi128_ps(first),_mm_castsi128_ps(second)));
295     }
296     else if (Offset==3)
297     {
298       first = _mm_castps_si128(_mm_move_ss(_mm_castsi128_ps(first),_mm_castsi128_ps(second)));
299       first = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(first),_mm_castsi128_ps(second),0x93));
300     }
301   }
302 };
303
304 template<int Offset>
305 struct ei_palign_impl<Offset,__m128d>
306 {
307   EIGEN_STRONG_INLINE static void run(__m128d& first, const __m128d& second)
308   {
309     if (Offset==1)
310     {
311       first = _mm_castps_pd(_mm_movehl_ps(_mm_castpd_ps(first),_mm_castpd_ps(first)));
312       first = _mm_castps_pd(_mm_movelh_ps(_mm_castpd_ps(first),_mm_castpd_ps(second)));
313     }
314   }
315 };
316 #endif
317
318 #define ei_vec4f_swizzle1(v,p,q,r,s) \
319   (_mm_castsi128_ps(_mm_shuffle_epi32( _mm_castps_si128(v), ((s)<<6|(r)<<4|(q)<<2|(p)))))
320
321 #endif // EIGEN_PACKET_MATH_SSE_H