EigenRand  0.4.0-alpha
arch/AVX/MorePacketMath.h
Go to the documentation of this file.
1 
12 #ifndef EIGENRAND_MORE_PACKET_MATH_AVX_H
13 #define EIGENRAND_MORE_PACKET_MATH_AVX_H
14 
15 #include <immintrin.h>
16 
17 namespace Eigen
18 {
19  namespace internal
20  {
21  template<>
22  struct IsIntPacket<Packet8i> : std::true_type {};
23 
24  template<>
25  struct HalfPacket<Packet8i>
26  {
27  using type = Packet4i;
28  };
29 
30  template<>
31  struct HalfPacket<Packet8f>
32  {
33  using type = Packet4f;
34  };
35 
36  template<>
37  struct IsFloatPacket<Packet8f> : std::true_type {};
38 
39  template<>
40  struct IsDoublePacket<Packet4d> : std::true_type {};
41 
42  template<>
43  struct reinterpreter<Packet8i>
44  {
45  EIGEN_STRONG_INLINE Packet8f to_float(const Packet8i& x)
46  {
47  return _mm256_castsi256_ps(x);
48  }
49 
50  EIGEN_STRONG_INLINE Packet4d to_double(const Packet8i& x)
51  {
52  return _mm256_castsi256_pd(x);
53  }
54 
55  EIGEN_STRONG_INLINE Packet8i to_int(const Packet8i& x)
56  {
57  return x;
58  }
59  };
60 
61  template<>
62  struct reinterpreter<Packet8f>
63  {
64  EIGEN_STRONG_INLINE Packet8f to_float(const Packet8f& x)
65  {
66  return x;
67  }
68 
69  EIGEN_STRONG_INLINE Packet4d to_double(const Packet8f& x)
70  {
71  return _mm256_castps_pd(x);
72  }
73 
74  EIGEN_STRONG_INLINE Packet8i to_int(const Packet8f& x)
75  {
76  return _mm256_castps_si256(x);
77  }
78  };
79 
80  template<>
81  struct reinterpreter<Packet4d>
82  {
83  EIGEN_STRONG_INLINE Packet8f to_float(const Packet4d& x)
84  {
85  return _mm256_castpd_ps(x);
86  }
87 
88  EIGEN_STRONG_INLINE Packet4d to_double(const Packet4d& x)
89  {
90  return x;
91  }
92 
93  EIGEN_STRONG_INLINE Packet8i to_int(const Packet4d& x)
94  {
95  return _mm256_castpd_si256(x);
96  }
97  };
98 
99  template<>
100  EIGEN_STRONG_INLINE void split_two<Packet8i>(const Packet8i& x, Packet4i& a, Packet4i& b)
101  {
102  a = _mm256_extractf128_si256(x, 0);
103  b = _mm256_extractf128_si256(x, 1);
104  }
105 
106  EIGEN_STRONG_INLINE Packet8i combine_two(const Packet4i& a, const Packet4i& b)
107  {
108  return _mm256_insertf128_si256(_mm256_castsi128_si256(a), b, 1);
109  }
110 
111  template<>
112  EIGEN_STRONG_INLINE void split_two<Packet8f>(const Packet8f& x, Packet4f& a, Packet4f& b)
113  {
114  a = _mm256_extractf128_ps(x, 0);
115  b = _mm256_extractf128_ps(x, 1);
116  }
117 
118  EIGEN_STRONG_INLINE Packet8f combine_two(const Packet4f& a, const Packet4f& b)
119  {
120  return _mm256_insertf128_ps(_mm256_castps128_ps256(a), b, 1);
121  }
122 
123 
124  EIGEN_STRONG_INLINE Packet4i combine_low32(const Packet8i& a)
125  {
126 #ifdef EIGEN_VECTORIZE_AVX2
127  return _mm256_castsi256_si128(_mm256_permutevar8x32_epi32(a, _mm256_setr_epi32(0, 2, 4, 6, 1, 3, 5, 7)));
128 #else
129  auto sc = _mm256_permutevar_ps(_mm256_castsi256_ps(a), _mm256_setr_epi32(0, 2, 1, 3, 1, 3, 0, 2));
130  return _mm_castps_si128(_mm_blend_ps(_mm256_extractf128_ps(sc, 0), _mm256_extractf128_ps(sc, 1), 0b1100));
131 #endif
132  }
133 
134  template<>
135  EIGEN_STRONG_INLINE Packet8i pseti64<Packet8i>(uint64_t a)
136  {
137  return _mm256_set1_epi64x(a);
138  }
139 
140  template<>
141  EIGEN_STRONG_INLINE Packet8i padd64<Packet8i>(const Packet8i& a, const Packet8i& b)
142  {
143 #ifdef EIGEN_VECTORIZE_AVX2
144  return _mm256_add_epi64(a, b);
145 #else
146  Packet4i a1, a2, b1, b2;
147  split_two(a, a1, a2);
148  split_two(b, b1, b2);
149  return combine_two((Packet4i)_mm_add_epi64(a1, b1), (Packet4i)_mm_add_epi64(a2, b2));
150 #endif
151  }
152 
153  template<>
154  EIGEN_STRONG_INLINE Packet8i psub64<Packet8i>(const Packet8i& a, const Packet8i& b)
155  {
156 #ifdef EIGEN_VECTORIZE_AVX2
157  return _mm256_sub_epi64(a, b);
158 #else
159  Packet4i a1, a2, b1, b2;
160  split_two(a, a1, a2);
161  split_two(b, b1, b2);
162  return combine_two((Packet4i)_mm_sub_epi64(a1, b1), (Packet4i)_mm_sub_epi64(a2, b2));
163 #endif
164  }
165 
166  template<>
167  EIGEN_STRONG_INLINE Packet8i pcmpeq<Packet8i>(const Packet8i& a, const Packet8i& b)
168  {
169 #ifdef EIGEN_VECTORIZE_AVX2
170  return _mm256_cmpeq_epi32(a, b);
171 #else
172  Packet4i a1, a2, b1, b2;
173  split_two(a, a1, a2);
174  split_two(b, b1, b2);
175  return combine_two((Packet4i)_mm_cmpeq_epi32(a1, b1), (Packet4i)_mm_cmpeq_epi32(a2, b2));
176 #endif
177  }
178 
179  template<>
180  struct BitShifter<Packet8i>
181  {
182  template<int b>
183  EIGEN_STRONG_INLINE Packet8i sll(const Packet8i& a)
184  {
185 #ifdef EIGEN_VECTORIZE_AVX2
186  return _mm256_slli_epi32(a, b);
187 #else
188  Packet4i a1, a2;
189  split_two(a, a1, a2);
190  return combine_two((Packet4i)_mm_slli_epi32(a1, b), (Packet4i)_mm_slli_epi32(a2, b));
191 #endif
192  }
193 
194  template<int b>
195  EIGEN_STRONG_INLINE Packet8i srl(const Packet8i& a, int _b = b)
196  {
197 #ifdef EIGEN_VECTORIZE_AVX2
198  if (b >= 0)
199  {
200  return _mm256_srli_epi32(a, b);
201  }
202  else
203  {
204  return _mm256_srli_epi32(a, _b);
205  }
206 #else
207  Packet4i a1, a2;
208  split_two(a, a1, a2);
209  if (b >= 0)
210  {
211  return combine_two((Packet4i)_mm_srli_epi32(a1, b), (Packet4i)_mm_srli_epi32(a2, b));
212  }
213  else
214  {
215  return combine_two((Packet4i)_mm_srli_epi32(a1, _b), (Packet4i)_mm_srli_epi32(a2, _b));
216  }
217 #endif
218  }
219 
220  template<int b>
221  EIGEN_STRONG_INLINE Packet8i sll64(const Packet8i& a)
222  {
223 #ifdef EIGEN_VECTORIZE_AVX2
224  return _mm256_slli_epi64(a, b);
225 #else
226  Packet4i a1, a2;
227  split_two(a, a1, a2);
228  return combine_two((Packet4i)_mm_slli_epi64(a1, b), (Packet4i)_mm_slli_epi64(a2, b));
229 #endif
230  }
231 
232  template<int b>
233  EIGEN_STRONG_INLINE Packet8i srl64(const Packet8i& a)
234  {
235 #ifdef EIGEN_VECTORIZE_AVX2
236  return _mm256_srli_epi64(a, b);
237 #else
238  Packet4i a1, a2;
239  split_two(a, a1, a2);
240  return combine_two((Packet4i)_mm_srli_epi64(a1, b), (Packet4i)_mm_srli_epi64(a2, b));
241 #endif
242  }
243  };
244 #ifdef EIGENRAND_EIGEN_33_MODE
245  template<> EIGEN_STRONG_INLINE Packet8i padd<Packet8i>(const Packet8i& a, const Packet8i& b)
246  {
247  #ifdef EIGEN_VECTORIZE_AVX2
248  return _mm256_add_epi32(a, b);
249  #else
250  Packet4i a1, a2, b1, b2;
251  split_two(a, a1, a2);
252  split_two(b, b1, b2);
253  return combine_two((Packet4i)_mm_add_epi32(a1, b1), (Packet4i)_mm_add_epi32(a2, b2));
254  #endif
255  }
256 
257  template<> EIGEN_STRONG_INLINE Packet8i psub<Packet8i>(const Packet8i& a, const Packet8i& b)
258  {
259  #ifdef EIGEN_VECTORIZE_AVX2
260  return _mm256_sub_epi32(a, b);
261  #else
262  Packet4i a1, a2, b1, b2;
263  split_two(a, a1, a2);
264  split_two(b, b1, b2);
265  return combine_two((Packet4i)_mm_sub_epi32(a1, b1), (Packet4i)_mm_sub_epi32(a2, b2));
266  #endif
267  }
268 
269  template<> EIGEN_STRONG_INLINE Packet8i pand<Packet8i>(const Packet8i& a, const Packet8i& b)
270  {
271  #ifdef EIGEN_VECTORIZE_AVX2
272  return _mm256_and_si256(a, b);
273  #else
274  return reinterpret_to_int((Packet8f)_mm256_and_ps(reinterpret_to_float(a), reinterpret_to_float(b)));
275  #endif
276  }
277 
278  template<> EIGEN_STRONG_INLINE Packet8i pandnot<Packet8i>(const Packet8i& a, const Packet8i& b)
279  {
280  #ifdef EIGEN_VECTORIZE_AVX2
281  return _mm256_andnot_si256(a, b);
282  #else
283  return reinterpret_to_int((Packet8f)_mm256_andnot_ps(reinterpret_to_float(a), reinterpret_to_float(b)));
284  #endif
285  }
286 
287  template<> EIGEN_STRONG_INLINE Packet8i por<Packet8i>(const Packet8i& a, const Packet8i& b)
288  {
289  #ifdef EIGEN_VECTORIZE_AVX2
290  return _mm256_or_si256(a, b);
291  #else
292  return reinterpret_to_int((Packet8f)_mm256_or_ps(reinterpret_to_float(a), reinterpret_to_float(b)));
293  #endif
294  }
295 
296  template<> EIGEN_STRONG_INLINE Packet8i pxor<Packet8i>(const Packet8i& a, const Packet8i& b)
297  {
298  #ifdef EIGEN_VECTORIZE_AVX2
299  return _mm256_xor_si256(a, b);
300  #else
301  return reinterpret_to_int((Packet8f)_mm256_xor_ps(reinterpret_to_float(a), reinterpret_to_float(b)));
302  #endif
303  }
304 #endif
305  template<>
306  EIGEN_STRONG_INLINE Packet8i pcmplt<Packet8i>(const Packet8i& a, const Packet8i& b)
307  {
308 #ifdef EIGEN_VECTORIZE_AVX2
309  return _mm256_cmpgt_epi32(b, a);
310 #else
311  Packet4i a1, a2, b1, b2;
312  split_two(a, a1, a2);
313  split_two(b, b1, b2);
314  return combine_two((Packet4i)_mm_cmpgt_epi32(b1, a1), (Packet4i)_mm_cmpgt_epi32(b2, a2));
315 #endif
316  }
317 
318  template<>
319  EIGEN_STRONG_INLINE Packet8i pcmplt64<Packet8i>(const Packet8i& a, const Packet8i& b)
320  {
321 #ifdef EIGEN_VECTORIZE_AVX2
322  return _mm256_cmpgt_epi64(b, a);
323 #else
324  Packet4i a1, a2, b1, b2;
325  split_two(a, a1, a2);
326  split_two(b, b1, b2);
327  return combine_two((Packet4i)_mm_cmpgt_epi64(b1, a1), (Packet4i)_mm_cmpgt_epi64(b2, a2));
328 #endif
329  }
330 
331  template<>
332  EIGEN_STRONG_INLINE Packet8f pcmplt<Packet8f>(const Packet8f& a, const Packet8f& b)
333  {
334  return _mm256_cmp_ps(a, b, _CMP_LT_OQ);
335  }
336 
337  template<>
338  EIGEN_STRONG_INLINE Packet8f pcmple<Packet8f>(const Packet8f& a, const Packet8f& b)
339  {
340  return _mm256_cmp_ps(a, b, _CMP_LE_OQ);
341  }
342 
343  template<>
344  EIGEN_STRONG_INLINE Packet4d pcmplt<Packet4d>(const Packet4d& a, const Packet4d& b)
345  {
346  return _mm256_cmp_pd(a, b, _CMP_LT_OQ);
347  }
348 
349  template<>
350  EIGEN_STRONG_INLINE Packet4d pcmple<Packet4d>(const Packet4d& a, const Packet4d& b)
351  {
352  return _mm256_cmp_pd(a, b, _CMP_LE_OQ);
353  }
354 
355  template<>
356  EIGEN_STRONG_INLINE Packet8f pblendv(const Packet8f& ifPacket, const Packet8f& thenPacket, const Packet8f& elsePacket)
357  {
358  return _mm256_blendv_ps(elsePacket, thenPacket, ifPacket);
359  }
360 
361  template<>
362  EIGEN_STRONG_INLINE Packet8f pblendv(const Packet8i& ifPacket, const Packet8f& thenPacket, const Packet8f& elsePacket)
363  {
364  return pblendv(_mm256_castsi256_ps(ifPacket), thenPacket, elsePacket);
365  }
366 
367  template<>
368  EIGEN_STRONG_INLINE Packet8i pblendv(const Packet8i& ifPacket, const Packet8i& thenPacket, const Packet8i& elsePacket)
369  {
370  return _mm256_castps_si256(_mm256_blendv_ps(
371  _mm256_castsi256_ps(elsePacket),
372  _mm256_castsi256_ps(thenPacket),
373  _mm256_castsi256_ps(ifPacket)
374  ));
375  }
376 
377  template<>
378  EIGEN_STRONG_INLINE Packet4d pblendv(const Packet4d& ifPacket, const Packet4d& thenPacket, const Packet4d& elsePacket)
379  {
380  return _mm256_blendv_pd(elsePacket, thenPacket, ifPacket);
381  }
382 
383  template<>
384  EIGEN_STRONG_INLINE Packet4d pblendv(const Packet8i& ifPacket, const Packet4d& thenPacket, const Packet4d& elsePacket)
385  {
386  return pblendv(_mm256_castsi256_pd(ifPacket), thenPacket, elsePacket);
387  }
388 
389  template<>
390  EIGEN_STRONG_INLINE Packet8i pgather<Packet8i>(const int* addr, const Packet8i& index)
391  {
392 #ifdef EIGEN_VECTORIZE_AVX2
393  return _mm256_i32gather_epi32(addr, index, 4);
394 #else
395  uint32_t u[8];
396  _mm256_storeu_si256((Packet8i*)u, index);
397  return _mm256_setr_epi32(addr[u[0]], addr[u[1]], addr[u[2]], addr[u[3]],
398  addr[u[4]], addr[u[5]], addr[u[6]], addr[u[7]]);
399 #endif
400  }
401 
402  template<>
403  EIGEN_STRONG_INLINE Packet8f pgather<Packet8i>(const float* addr, const Packet8i& index)
404  {
405 #ifdef EIGEN_VECTORIZE_AVX2
406  return _mm256_i32gather_ps(addr, index, 4);
407 #else
408  uint32_t u[8];
409  _mm256_storeu_si256((Packet8i*)u, index);
410  return _mm256_setr_ps(addr[u[0]], addr[u[1]], addr[u[2]], addr[u[3]],
411  addr[u[4]], addr[u[5]], addr[u[6]], addr[u[7]]);
412 #endif
413  }
414 
415  template<>
416  EIGEN_STRONG_INLINE Packet4d pgather<Packet8i>(const double* addr, const Packet8i& index, bool upperhalf)
417  {
418 #ifdef EIGEN_VECTORIZE_AVX2
419  return _mm256_i32gather_pd(addr, _mm256_castsi256_si128(index), 8);
420 #else
421  uint32_t u[8];
422  _mm256_storeu_si256((Packet8i*)u, index);
423  if (upperhalf)
424  {
425  return _mm256_setr_pd(addr[u[4]], addr[u[5]], addr[u[6]], addr[u[7]]);
426  }
427  else
428  {
429  return _mm256_setr_pd(addr[u[0]], addr[u[1]], addr[u[2]], addr[u[3]]);
430  }
431 #endif
432  }
433 
434  template<>
435  EIGEN_STRONG_INLINE int pmovemask<Packet8f>(const Packet8f& a)
436  {
437  return _mm256_movemask_ps(a);
438  }
439 
440  template<>
441  EIGEN_STRONG_INLINE int pmovemask<Packet4d>(const Packet4d& a)
442  {
443  return _mm256_movemask_pd(a);
444  }
445 
446  template<>
447  EIGEN_STRONG_INLINE int pmovemask<Packet8i>(const Packet8i& a)
448  {
449  return pmovemask(_mm256_castsi256_ps(a));
450  }
451 
452  template<>
453  EIGEN_STRONG_INLINE Packet8f ptruncate<Packet8f>(const Packet8f& a)
454  {
455  return _mm256_round_ps(a, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC);
456  }
457 
458  template<>
459  EIGEN_STRONG_INLINE Packet4d ptruncate<Packet4d>(const Packet4d& a)
460  {
461  return _mm256_round_pd(a, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC);
462  }
463 
464  template<>
465  EIGEN_STRONG_INLINE Packet8i pcmpeq64<Packet8i>(const Packet8i& a, const Packet8i& b)
466  {
467 #ifdef EIGEN_VECTORIZE_AVX2
468  return _mm256_cmpeq_epi64(a, b);
469 #else
470  Packet4i a1, a2, b1, b2;
471  split_two(a, a1, a2);
472  split_two(b, b1, b2);
473  return combine_two((Packet4i)_mm_cmpeq_epi64(a1, b1), (Packet4i)_mm_cmpeq_epi64(a2, b2));
474 #endif
475  }
476 
477  template<>
478  EIGEN_STRONG_INLINE Packet8i pmuluadd64<Packet8i>(const Packet8i& a, uint64_t b, uint64_t c)
479  {
480  uint64_t u[4];
481  _mm256_storeu_si256((__m256i*)u, a);
482  u[0] = u[0] * b + c;
483  u[1] = u[1] * b + c;
484  u[2] = u[2] * b + c;
485  u[3] = u[3] * b + c;
486  return _mm256_loadu_si256((__m256i*)u);
487  }
488 
489  EIGEN_STRONG_INLINE __m256d uint64_to_double(__m256i x) {
490  auto y = _mm256_or_pd(_mm256_castsi256_pd(x), _mm256_set1_pd(0x0010000000000000));
491  return _mm256_sub_pd(y, _mm256_set1_pd(0x0010000000000000));
492  }
493 
494  EIGEN_STRONG_INLINE __m256d int64_to_double(__m256i x) {
495  x = padd64(x, _mm256_castpd_si256(_mm256_set1_pd(0x0018000000000000)));
496  return _mm256_sub_pd(_mm256_castsi256_pd(x), _mm256_set1_pd(0x0018000000000000));
497  }
498 
499  EIGEN_STRONG_INLINE __m256i double_to_int64(__m256d x) {
500  x = _mm256_add_pd(_mm256_floor_pd(x), _mm256_set1_pd(0x0018000000000000));
501  return psub64(
502  _mm256_castpd_si256(x),
503  _mm256_castpd_si256(_mm256_set1_pd(0x0018000000000000))
504  );
505  }
506 
507  template<>
508  EIGEN_STRONG_INLINE Packet8i pcast64<Packet4d, Packet8i>(const Packet4d& a)
509  {
510  return double_to_int64(a);
511  }
512 
513  template<>
514  EIGEN_STRONG_INLINE Packet4d pcast64<Packet8i, Packet4d>(const Packet8i& a)
515  {
516  return int64_to_double(a);
517  }
518 
519  template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED
520  Packet4d psin<Packet4d>(const Packet4d& x)
521  {
522  return _psin(x);
523  }
524 
525  #ifdef EIGENRAND_EIGEN_33_MODE
526  template <>
527  EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet4d
528  plog<Packet4d>(const Packet4d& _x) {
529  Packet4d x = _x;
530  _EIGEN_DECLARE_CONST_Packet4d(1, 1.0);
531  _EIGEN_DECLARE_CONST_Packet4d(half, 0.5);
532 
533  auto inv_mant_mask = _mm256_castsi256_pd(pseti64<Packet8i>(~0x7ff0000000000000));
534  auto min_norm_pos = _mm256_castsi256_pd(pseti64<Packet8i>(0x10000000000000));
535  auto minus_inf = _mm256_castsi256_pd(pseti64<Packet8i>(0xfff0000000000000));
536 
537  // Polynomial coefficients.
538  _EIGEN_DECLARE_CONST_Packet4d(cephes_SQRTHF, 0.707106781186547524);
539  _EIGEN_DECLARE_CONST_Packet4d(cephes_log_p0, 7.0376836292E-2);
540  _EIGEN_DECLARE_CONST_Packet4d(cephes_log_p1, -1.1514610310E-1);
541  _EIGEN_DECLARE_CONST_Packet4d(cephes_log_p2, 1.1676998740E-1);
542  _EIGEN_DECLARE_CONST_Packet4d(cephes_log_p3, -1.2420140846E-1);
543  _EIGEN_DECLARE_CONST_Packet4d(cephes_log_p4, +1.4249322787E-1);
544  _EIGEN_DECLARE_CONST_Packet4d(cephes_log_p5, -1.6668057665E-1);
545  _EIGEN_DECLARE_CONST_Packet4d(cephes_log_p6, +2.0000714765E-1);
546  _EIGEN_DECLARE_CONST_Packet4d(cephes_log_p7, -2.4999993993E-1);
547  _EIGEN_DECLARE_CONST_Packet4d(cephes_log_p8, +3.3333331174E-1);
548  _EIGEN_DECLARE_CONST_Packet4d(cephes_log_q1, -2.12194440e-4);
549  _EIGEN_DECLARE_CONST_Packet4d(cephes_log_q2, 0.693359375);
550 
551  Packet4d invalid_mask = _mm256_cmp_pd(x, _mm256_setzero_pd(), _CMP_NGE_UQ); // not greater equal is true if x is NaN
552  Packet4d iszero_mask = _mm256_cmp_pd(x, _mm256_setzero_pd(), _CMP_EQ_OQ);
553 
554  // Truncate input values to the minimum positive normal.
555  x = pmax(x, min_norm_pos);
556 
557  Packet4d emm0 = uint64_to_double(psrl64<52>(_mm256_castpd_si256(x)));
558  Packet4d e = psub(emm0, pset1<Packet4d>(1022));
559 
560  // Set the exponents to -1, i.e. x are in the range [0.5,1).
561  x = _mm256_and_pd(x, inv_mant_mask);
562  x = _mm256_or_pd(x, p4d_half);
563 
564  // part2: Shift the inputs from the range [0.5,1) to [sqrt(1/2),sqrt(2))
565  // and shift by -1. The values are then centered around 0, which improves
566  // the stability of the polynomial evaluation.
567  // if( x < SQRTHF ) {
568  // e -= 1;
569  // x = x + x - 1.0;
570  // } else { x = x - 1.0; }
571  Packet4d mask = _mm256_cmp_pd(x, p4d_cephes_SQRTHF, _CMP_LT_OQ);
572  Packet4d tmp = _mm256_and_pd(x, mask);
573  x = psub(x, p4d_1);
574  e = psub(e, _mm256_and_pd(p4d_1, mask));
575  x = padd(x, tmp);
576 
577  Packet4d x2 = pmul(x, x);
578  Packet4d x3 = pmul(x2, x);
579 
580  // Evaluate the polynomial approximant of degree 8 in three parts, probably
581  // to improve instruction-level parallelism.
582  Packet4d y, y1, y2;
583  y = pmadd(p4d_cephes_log_p0, x, p4d_cephes_log_p1);
584  y1 = pmadd(p4d_cephes_log_p3, x, p4d_cephes_log_p4);
585  y2 = pmadd(p4d_cephes_log_p6, x, p4d_cephes_log_p7);
586  y = pmadd(y, x, p4d_cephes_log_p2);
587  y1 = pmadd(y1, x, p4d_cephes_log_p5);
588  y2 = pmadd(y2, x, p4d_cephes_log_p8);
589  y = pmadd(y, x3, y1);
590  y = pmadd(y, x3, y2);
591  y = pmul(y, x3);
592 
593  // Add the logarithm of the exponent back to the result of the interpolation.
594  y1 = pmul(e, p4d_cephes_log_q1);
595  tmp = pmul(x2, p4d_half);
596  y = padd(y, y1);
597  x = psub(x, tmp);
598  y2 = pmul(e, p4d_cephes_log_q2);
599  x = padd(x, y);
600  x = padd(x, y2);
601 
602  // Filter out invalid inputs, i.e. negative arg will be NAN, 0 will be -INF.
603  return pblendv(iszero_mask, minus_inf, _mm256_or_pd(x, invalid_mask));
604  }
605  #endif
606 
607  #if !(EIGEN_VERSION_AT_LEAST(3,3,5))
608  template<> EIGEN_STRONG_INLINE Packet4f pcast<Packet4i, Packet4f>(const Packet4i& a) {
609  return _mm_cvtepi32_ps(a);
610  }
611 
612  template<> EIGEN_STRONG_INLINE Packet4i pcast<Packet4f, Packet4i>(const Packet4f& a) {
613  return _mm_cvttps_epi32(a);
614  }
615  #endif
616  }
617 }
618 
619 #endif