GPU/PacketMath.h
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
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_PACKET_MATH_GPU_H
11 #define EIGEN_PACKET_MATH_GPU_H
12 
13 #include "../../InternalHeaderCheck.h"
14 
15 namespace Eigen {
16 
17 namespace internal {
18 
19 // Read-only data cached load available.
20 #if defined(EIGEN_HIP_DEVICE_COMPILE) || (defined(EIGEN_CUDA_ARCH) && EIGEN_CUDA_ARCH >= 350)
21 #define EIGEN_GPU_HAS_LDG 1
22 #endif
23 
24 // FP16 math available.
25 #if (defined(EIGEN_CUDA_ARCH) && EIGEN_CUDA_ARCH >= 530)
26 #define EIGEN_CUDA_HAS_FP16_ARITHMETIC 1
27 #endif
28 
29 #if defined(EIGEN_HIP_DEVICE_COMPILE) || defined(EIGEN_CUDA_HAS_FP16_ARITHMETIC)
30 #define EIGEN_GPU_HAS_FP16_ARITHMETIC 1
31 #endif
32 
33 // Make sure this is only available when targeting a GPU: we don't want to
34 // introduce conflicts between these packet_traits definitions and the ones
35 // we'll use on the host side (SSE, AVX, ...)
36 #if defined(EIGEN_GPUCC) && defined(EIGEN_USE_GPU)
37 
38 template<> struct is_arithmetic<float4> { enum { value = true }; };
39 template<> struct is_arithmetic<double2> { enum { value = true }; };
40 
41 template<> struct packet_traits<float> : default_packet_traits
42 {
43  typedef float4 type;
44  typedef float4 half;
45  enum {
46  Vectorizable = 1,
47  AlignedOnScalar = 1,
48  size=4,
49 
50  HasDiv = 1,
51  HasSin = 0,
52  HasCos = 0,
53  HasLog = 1,
54  HasExp = 1,
55  HasSqrt = 1,
56  HasRsqrt = 1,
57  HasLGamma = 1,
58  HasDiGamma = 1,
59  HasZeta = 1,
60  HasPolygamma = 1,
61  HasErf = 1,
62  HasErfc = 1,
63  HasNdtri = 1,
64  HasBessel = 1,
65  HasIGamma = 1,
66  HasIGammaDerA = 1,
67  HasGammaSampleDerAlpha = 1,
68  HasIGammac = 1,
69  HasBetaInc = 1,
70 
71  HasBlend = 0,
72  HasFloor = 1,
73  };
74 };
75 
76 template<> struct packet_traits<double> : default_packet_traits
77 {
78  typedef double2 type;
79  typedef double2 half;
80  enum {
81  Vectorizable = 1,
82  AlignedOnScalar = 1,
83  size=2,
84 
85  HasDiv = 1,
86  HasLog = 1,
87  HasExp = 1,
88  HasSqrt = 1,
89  HasRsqrt = 1,
90  HasLGamma = 1,
91  HasDiGamma = 1,
92  HasZeta = 1,
93  HasPolygamma = 1,
94  HasErf = 1,
95  HasErfc = 1,
96  HasNdtri = 1,
97  HasBessel = 1,
98  HasIGamma = 1,
99  HasIGammaDerA = 1,
100  HasGammaSampleDerAlpha = 1,
101  HasIGammac = 1,
102  HasBetaInc = 1,
103 
104  HasBlend = 0,
105  HasFloor = 1,
106  };
107 };
108 
109 
110 template<> struct unpacket_traits<float4> { typedef float type; enum {size=4, alignment=Aligned16, vectorizable=true, masked_load_available=false, masked_store_available=false}; typedef float4 half; };
111 template<> struct unpacket_traits<double2> { typedef double type; enum {size=2, alignment=Aligned16, vectorizable=true, masked_load_available=false, masked_store_available=false}; typedef double2 half; };
112 
113 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pset1<float4>(const float& from) {
114  return make_float4(from, from, from, from);
115 }
116 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pset1<double2>(const double& from) {
117  return make_double2(from, from);
118 }
119 
120 // We need to distinguish ‘clang as the CUDA compiler’ from ‘clang as the host compiler,
121 // invoked by NVCC’ (e.g. on MacOS). The former needs to see both host and device implementation
122 // of the functions, while the latter can only deal with one of them.
123 #if defined(EIGEN_CUDA_ARCH) || defined(EIGEN_HIPCC) || (defined(EIGEN_CUDACC) && EIGEN_COMP_CLANG && !EIGEN_COMP_NVCC)
124 
125 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float bitwise_and(const float& a,
126  const float& b) {
127  return __int_as_float(__float_as_int(a) & __float_as_int(b));
128 }
129 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double bitwise_and(const double& a,
130  const double& b) {
131  return __longlong_as_double(__double_as_longlong(a) &
132  __double_as_longlong(b));
133 }
134 
135 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float bitwise_or(const float& a,
136  const float& b) {
137  return __int_as_float(__float_as_int(a) | __float_as_int(b));
138 }
139 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double bitwise_or(const double& a,
140  const double& b) {
141  return __longlong_as_double(__double_as_longlong(a) |
142  __double_as_longlong(b));
143 }
144 
145 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float bitwise_xor(const float& a,
146  const float& b) {
147  return __int_as_float(__float_as_int(a) ^ __float_as_int(b));
148 }
149 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double bitwise_xor(const double& a,
150  const double& b) {
151  return __longlong_as_double(__double_as_longlong(a) ^
152  __double_as_longlong(b));
153 }
154 
155 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float bitwise_andnot(const float& a,
156  const float& b) {
157  return __int_as_float(__float_as_int(a) & ~__float_as_int(b));
158 }
159 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double bitwise_andnot(const double& a,
160  const double& b) {
161  return __longlong_as_double(__double_as_longlong(a) &
162  ~__double_as_longlong(b));
163 }
164 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float eq_mask(const float& a,
165  const float& b) {
166  return __int_as_float(a == b ? 0xffffffffu : 0u);
167 }
168 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double eq_mask(const double& a,
169  const double& b) {
170  return __longlong_as_double(a == b ? 0xffffffffffffffffull : 0ull);
171 }
172 
173 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float lt_mask(const float& a,
174  const float& b) {
175  return __int_as_float(a < b ? 0xffffffffu : 0u);
176 }
177 
178 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double lt_mask(const double& a,
179  const double& b) {
180  return __longlong_as_double(a < b ? 0xffffffffffffffffull : 0ull);
181 }
182 
183 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float le_mask(const float& a,
184  const float& b) {
185  return __int_as_float(a <= b ? 0xffffffffu : 0u);
186 }
187 
188 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double le_mask(const double& a,
189  const double& b) {
190  return __longlong_as_double(a <= b ? 0xffffffffffffffffull : 0ull);
191 }
192 
193 template <>
194 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pand<float4>(const float4& a,
195  const float4& b) {
196  return make_float4(bitwise_and(a.x, b.x), bitwise_and(a.y, b.y),
197  bitwise_and(a.z, b.z), bitwise_and(a.w, b.w));
198 }
199 template <>
200 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pand<double2>(const double2& a,
201  const double2& b) {
202  return make_double2(bitwise_and(a.x, b.x), bitwise_and(a.y, b.y));
203 }
204 
205 template <>
206 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 por<float4>(const float4& a,
207  const float4& b) {
208  return make_float4(bitwise_or(a.x, b.x), bitwise_or(a.y, b.y),
209  bitwise_or(a.z, b.z), bitwise_or(a.w, b.w));
210 }
211 template <>
212 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 por<double2>(const double2& a,
213  const double2& b) {
214  return make_double2(bitwise_or(a.x, b.x), bitwise_or(a.y, b.y));
215 }
216 
217 template <>
218 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pxor<float4>(const float4& a,
219  const float4& b) {
220  return make_float4(bitwise_xor(a.x, b.x), bitwise_xor(a.y, b.y),
221  bitwise_xor(a.z, b.z), bitwise_xor(a.w, b.w));
222 }
223 template <>
224 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pxor<double2>(const double2& a,
225  const double2& b) {
226  return make_double2(bitwise_xor(a.x, b.x), bitwise_xor(a.y, b.y));
227 }
228 
229 template <>
230 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pandnot<float4>(const float4& a,
231  const float4& b) {
232  return make_float4(bitwise_andnot(a.x, b.x), bitwise_andnot(a.y, b.y),
233  bitwise_andnot(a.z, b.z), bitwise_andnot(a.w, b.w));
234 }
235 template <>
236 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2
237 pandnot<double2>(const double2& a, const double2& b) {
238  return make_double2(bitwise_andnot(a.x, b.x), bitwise_andnot(a.y, b.y));
239 }
240 
241 template <>
242 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pcmp_eq<float4>(const float4& a,
243  const float4& b) {
244  return make_float4(eq_mask(a.x, b.x), eq_mask(a.y, b.y), eq_mask(a.z, b.z),
245  eq_mask(a.w, b.w));
246 }
247 template <>
248 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pcmp_lt<float4>(const float4& a,
249  const float4& b) {
250  return make_float4(lt_mask(a.x, b.x), lt_mask(a.y, b.y), lt_mask(a.z, b.z),
251  lt_mask(a.w, b.w));
252 }
253 template <>
254 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pcmp_le<float4>(const float4& a,
255  const float4& b) {
256  return make_float4(le_mask(a.x, b.x), le_mask(a.y, b.y), le_mask(a.z, b.z),
257  le_mask(a.w, b.w));
258 }
259 template <>
260 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2
261 pcmp_eq<double2>(const double2& a, const double2& b) {
262  return make_double2(eq_mask(a.x, b.x), eq_mask(a.y, b.y));
263 }
264 template <>
265 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2
266 pcmp_lt<double2>(const double2& a, const double2& b) {
267  return make_double2(lt_mask(a.x, b.x), lt_mask(a.y, b.y));
268 }
269 template <>
270 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2
271 pcmp_le<double2>(const double2& a, const double2& b) {
272  return make_double2(le_mask(a.x, b.x), le_mask(a.y, b.y));
273 }
274 #endif // defined(EIGEN_CUDA_ARCH) || defined(EIGEN_HIPCC) || (defined(EIGEN_CUDACC) && EIGEN_COMP_CLANG && !EIGEN_COMP_NVCC)
275 
276 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 plset<float4>(const float& a) {
277  return make_float4(a, a+1, a+2, a+3);
278 }
279 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 plset<double2>(const double& a) {
280  return make_double2(a, a+1);
281 }
282 
283 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 padd<float4>(const float4& a, const float4& b) {
284  return make_float4(a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w);
285 }
286 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 padd<double2>(const double2& a, const double2& b) {
287  return make_double2(a.x+b.x, a.y+b.y);
288 }
289 
290 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 psub<float4>(const float4& a, const float4& b) {
291  return make_float4(a.x-b.x, a.y-b.y, a.z-b.z, a.w-b.w);
292 }
293 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 psub<double2>(const double2& a, const double2& b) {
294  return make_double2(a.x-b.x, a.y-b.y);
295 }
296 
297 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pnegate(const float4& a) {
298  return make_float4(-a.x, -a.y, -a.z, -a.w);
299 }
300 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pnegate(const double2& a) {
301  return make_double2(-a.x, -a.y);
302 }
303 
304 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pconj(const float4& a) { return a; }
305 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pconj(const double2& a) { return a; }
306 
307 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pmul<float4>(const float4& a, const float4& b) {
308  return make_float4(a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w);
309 }
310 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pmul<double2>(const double2& a, const double2& b) {
311  return make_double2(a.x*b.x, a.y*b.y);
312 }
313 
314 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pdiv<float4>(const float4& a, const float4& b) {
315  return make_float4(a.x/b.x, a.y/b.y, a.z/b.z, a.w/b.w);
316 }
317 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pdiv<double2>(const double2& a, const double2& b) {
318  return make_double2(a.x/b.x, a.y/b.y);
319 }
320 
321 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pmin<float4>(const float4& a, const float4& b) {
322  return make_float4(fminf(a.x, b.x), fminf(a.y, b.y), fminf(a.z, b.z), fminf(a.w, b.w));
323 }
324 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pmin<double2>(const double2& a, const double2& b) {
325  return make_double2(fmin(a.x, b.x), fmin(a.y, b.y));
326 }
327 
328 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pmax<float4>(const float4& a, const float4& b) {
329  return make_float4(fmaxf(a.x, b.x), fmaxf(a.y, b.y), fmaxf(a.z, b.z), fmaxf(a.w, b.w));
330 }
331 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pmax<double2>(const double2& a, const double2& b) {
332  return make_double2(fmax(a.x, b.x), fmax(a.y, b.y));
333 }
334 
335 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 pload<float4>(const float* from) {
336  return *reinterpret_cast<const float4*>(from);
337 }
338 
339 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 pload<double2>(const double* from) {
340  return *reinterpret_cast<const double2*>(from);
341 }
342 
343 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 ploadu<float4>(const float* from) {
344  return make_float4(from[0], from[1], from[2], from[3]);
345 }
346 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 ploadu<double2>(const double* from) {
347  return make_double2(from[0], from[1]);
348 }
349 
350 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE float4 ploaddup<float4>(const float* from) {
351  return make_float4(from[0], from[0], from[1], from[1]);
352 }
353 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double2 ploaddup<double2>(const double* from) {
354  return make_double2(from[0], from[0]);
355 }
356 
357 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pstore<float>(float* to, const float4& from) {
358  *reinterpret_cast<float4*>(to) = from;
359 }
360 
361 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pstore<double>(double* to, const double2& from) {
362  *reinterpret_cast<double2*>(to) = from;
363 }
364 
365 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pstoreu<float>(float* to, const float4& from) {
366  to[0] = from.x;
367  to[1] = from.y;
368  to[2] = from.z;
369  to[3] = from.w;
370 }
371 
372 template<> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pstoreu<double>(double* to, const double2& from) {
373  to[0] = from.x;
374  to[1] = from.y;
375 }
376 
377 template<>
378 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float4 ploadt_ro<float4, Aligned>(const float* from) {
379 #if defined(EIGEN_GPU_HAS_LDG)
380  return __ldg(reinterpret_cast<const float4*>(from));
381 #else
382  return make_float4(from[0], from[1], from[2], from[3]);
383 #endif
384 }
385 template<>
386 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double2 ploadt_ro<double2, Aligned>(const double* from) {
387 #if defined(EIGEN_GPU_HAS_LDG)
388  return __ldg(reinterpret_cast<const double2*>(from));
389 #else
390  return make_double2(from[0], from[1]);
391 #endif
392 }
393 
394 template<>
395 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float4 ploadt_ro<float4, Unaligned>(const float* from) {
396 #if defined(EIGEN_GPU_HAS_LDG)
397  return make_float4(__ldg(from+0), __ldg(from+1), __ldg(from+2), __ldg(from+3));
398 #else
399  return make_float4(from[0], from[1], from[2], from[3]);
400 #endif
401 }
402 template<>
403 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double2 ploadt_ro<double2, Unaligned>(const double* from) {
404 #if defined(EIGEN_GPU_HAS_LDG)
405  return make_double2(__ldg(from+0), __ldg(from+1));
406 #else
407  return make_double2(from[0], from[1]);
408 #endif
409 }
410 
411 template<> EIGEN_DEVICE_FUNC inline float4 pgather<float, float4>(const float* from, Index stride) {
412  return make_float4(from[0*stride], from[1*stride], from[2*stride], from[3*stride]);
413 }
414 
415 template<> EIGEN_DEVICE_FUNC inline double2 pgather<double, double2>(const double* from, Index stride) {
416  return make_double2(from[0*stride], from[1*stride]);
417 }
418 
419 template<> EIGEN_DEVICE_FUNC inline void pscatter<float, float4>(float* to, const float4& from, Index stride) {
420  to[stride*0] = from.x;
421  to[stride*1] = from.y;
422  to[stride*2] = from.z;
423  to[stride*3] = from.w;
424 }
425 template<> EIGEN_DEVICE_FUNC inline void pscatter<double, double2>(double* to, const double2& from, Index stride) {
426  to[stride*0] = from.x;
427  to[stride*1] = from.y;
428 }
429 
430 template<> EIGEN_DEVICE_FUNC inline float pfirst<float4>(const float4& a) {
431  return a.x;
432 }
433 template<> EIGEN_DEVICE_FUNC inline double pfirst<double2>(const double2& a) {
434  return a.x;
435 }
436 
437 template<> EIGEN_DEVICE_FUNC inline float predux<float4>(const float4& a) {
438  return a.x + a.y + a.z + a.w;
439 }
440 template<> EIGEN_DEVICE_FUNC inline double predux<double2>(const double2& a) {
441  return a.x + a.y;
442 }
443 
444 template<> EIGEN_DEVICE_FUNC inline float predux_max<float4>(const float4& a) {
445  return fmaxf(fmaxf(a.x, a.y), fmaxf(a.z, a.w));
446 }
447 template<> EIGEN_DEVICE_FUNC inline double predux_max<double2>(const double2& a) {
448  return fmax(a.x, a.y);
449 }
450 
451 template<> EIGEN_DEVICE_FUNC inline float predux_min<float4>(const float4& a) {
452  return fminf(fminf(a.x, a.y), fminf(a.z, a.w));
453 }
454 template<> EIGEN_DEVICE_FUNC inline double predux_min<double2>(const double2& a) {
455  return fmin(a.x, a.y);
456 }
457 
458 template<> EIGEN_DEVICE_FUNC inline float predux_mul<float4>(const float4& a) {
459  return a.x * a.y * a.z * a.w;
460 }
461 template<> EIGEN_DEVICE_FUNC inline double predux_mul<double2>(const double2& a) {
462  return a.x * a.y;
463 }
464 
465 template<> EIGEN_DEVICE_FUNC inline float4 pabs<float4>(const float4& a) {
466  return make_float4(fabsf(a.x), fabsf(a.y), fabsf(a.z), fabsf(a.w));
467 }
468 template<> EIGEN_DEVICE_FUNC inline double2 pabs<double2>(const double2& a) {
469  return make_double2(fabs(a.x), fabs(a.y));
470 }
471 
472 template<> EIGEN_DEVICE_FUNC inline float4 pfloor<float4>(const float4& a) {
473  return make_float4(floorf(a.x), floorf(a.y), floorf(a.z), floorf(a.w));
474 }
475 template<> EIGEN_DEVICE_FUNC inline double2 pfloor<double2>(const double2& a) {
476  return make_double2(floor(a.x), floor(a.y));
477 }
478 
479 EIGEN_DEVICE_FUNC inline void
480 ptranspose(PacketBlock<float4,4>& kernel) {
481  float tmp = kernel.packet[0].y;
482  kernel.packet[0].y = kernel.packet[1].x;
483  kernel.packet[1].x = tmp;
484 
485  tmp = kernel.packet[0].z;
486  kernel.packet[0].z = kernel.packet[2].x;
487  kernel.packet[2].x = tmp;
488 
489  tmp = kernel.packet[0].w;
490  kernel.packet[0].w = kernel.packet[3].x;
491  kernel.packet[3].x = tmp;
492 
493  tmp = kernel.packet[1].z;
494  kernel.packet[1].z = kernel.packet[2].y;
495  kernel.packet[2].y = tmp;
496 
497  tmp = kernel.packet[1].w;
498  kernel.packet[1].w = kernel.packet[3].y;
499  kernel.packet[3].y = tmp;
500 
501  tmp = kernel.packet[2].w;
502  kernel.packet[2].w = kernel.packet[3].z;
503  kernel.packet[3].z = tmp;
504 }
505 
506 EIGEN_DEVICE_FUNC inline void
507 ptranspose(PacketBlock<double2,2>& kernel) {
508  double tmp = kernel.packet[0].y;
509  kernel.packet[0].y = kernel.packet[1].x;
510  kernel.packet[1].x = tmp;
511 }
512 
513 #endif // defined(EIGEN_GPUCC) && defined(EIGEN_USE_GPU)
514 
515 // Half-packet functions are not available on the host for CUDA 9.0-9.2, only
516 // on device. There is no benefit to using them on the host anyways, since they are
517 // emulated.
518 #if (defined(EIGEN_HAS_CUDA_FP16) || defined(EIGEN_HAS_HIP_FP16)) && defined(EIGEN_GPU_COMPILE_PHASE)
519 
520 typedef ulonglong2 Packet4h2;
521 template<> struct unpacket_traits<Packet4h2> { typedef Eigen::half type; enum {size=8, alignment=Aligned16, vectorizable=true, masked_load_available=false, masked_store_available=false}; typedef Packet4h2 half; };
522 template<> struct is_arithmetic<Packet4h2> { enum { value = true }; };
523 
524 template<> struct unpacket_traits<half2> { typedef Eigen::half type; enum {size=2, alignment=Aligned16, vectorizable=true, masked_load_available=false, masked_store_available=false}; typedef half2 half; };
525 template<> struct is_arithmetic<half2> { enum { value = true }; };
526 
527 template<> struct packet_traits<Eigen::half> : default_packet_traits
528 {
529  typedef Packet4h2 type;
530  typedef Packet4h2 half;
531  enum {
532  Vectorizable = 1,
533  AlignedOnScalar = 1,
534  size=8,
535  HasAdd = 1,
536  HasSub = 1,
537  HasMul = 1,
538  HasDiv = 1,
539  HasSqrt = 1,
540  HasRsqrt = 1,
541  HasExp = 1,
542  HasExpm1 = 1,
543  HasLog = 1,
544  HasLog1p = 1
545  };
546 };
547 
548 template<>
549 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pset1<half2>(const Eigen::half& from) {
550  return __half2half2(from);
551 }
552 
553 template <>
554 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2
555 pset1<Packet4h2>(const Eigen::half& from) {
556  Packet4h2 r;
557  half2* p_alias = reinterpret_cast<half2*>(&r);
558  p_alias[0] = pset1<half2>(from);
559  p_alias[1] = pset1<half2>(from);
560  p_alias[2] = pset1<half2>(from);
561  p_alias[3] = pset1<half2>(from);
562  return r;
563 }
564 
565 namespace {
566 
567 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pload(const Eigen::half* from) {
568  return *reinterpret_cast<const half2*>(from);
569 }
570 
571 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 ploadu(const Eigen::half* from) {
572  return __halves2half2(from[0], from[1]);
573 }
574 
575 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 ploaddup(const Eigen::half* from) {
576  return __halves2half2(from[0], from[0]);
577 }
578 
579 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pstore(Eigen::half* to,
580  const half2& from) {
581  *reinterpret_cast<half2*>(to) = from;
582 }
583 
584 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pstoreu(Eigen::half* to,
585  const half2& from) {
586  to[0] = __low2half(from);
587  to[1] = __high2half(from);
588 }
589 
590 
591 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE half2 ploadt_ro_aligned(
592  const Eigen::half* from) {
593 #if defined(EIGEN_GPU_HAS_LDG)
594  // Input is guaranteed to be properly aligned.
595  return __ldg(reinterpret_cast<const half2*>(from));
596 #else
597  return __halves2half2(*(from+0), *(from+1));
598 #endif
599 }
600 
601 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE half2 ploadt_ro_unaligned(
602  const Eigen::half* from) {
603 #if defined(EIGEN_GPU_HAS_LDG)
604  return __halves2half2(__ldg(from+0), __ldg(from+1));
605 #else
606  return __halves2half2(*(from+0), *(from+1));
607 #endif
608 }
609 
610 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pgather(const Eigen::half* from,
611  Index stride) {
612  return __halves2half2(from[0*stride], from[1*stride]);
613 }
614 
615 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter(
616  Eigen::half* to, const half2& from, Index stride) {
617  to[stride*0] = __low2half(from);
618  to[stride*1] = __high2half(from);
619 }
620 
621 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::half pfirst(const half2& a) {
622  return __low2half(a);
623 }
624 
625 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pabs(const half2& a) {
626  half a1 = __low2half(a);
627  half a2 = __high2half(a);
628  half result1 = half_impl::raw_uint16_to_half(a1.x & 0x7FFF);
629  half result2 = half_impl::raw_uint16_to_half(a2.x & 0x7FFF);
630  return __halves2half2(result1, result2);
631 }
632 
633 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 ptrue(const half2& /*a*/) {
634  half true_half = half_impl::raw_uint16_to_half(0xffffu);
635  return pset1<half2>(true_half);
636 }
637 
638 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pzero(const half2& /*a*/) {
639  half false_half = half_impl::raw_uint16_to_half(0x0000u);
640  return pset1<half2>(false_half);
641 }
642 
643 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void
644 ptranspose(PacketBlock<half2,2>& kernel) {
645  __half a1 = __low2half(kernel.packet[0]);
646  __half a2 = __high2half(kernel.packet[0]);
647  __half b1 = __low2half(kernel.packet[1]);
648  __half b2 = __high2half(kernel.packet[1]);
649  kernel.packet[0] = __halves2half2(a1, b1);
650  kernel.packet[1] = __halves2half2(a2, b2);
651 }
652 
653 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 plset(const Eigen::half& a) {
654 #if defined(EIGEN_GPU_HAS_FP16_ARITHMETIC)
655  return __halves2half2(a, __hadd(a, __float2half(1.0f)));
656 #else
657  float f = __half2float(a) + 1.0f;
658  return __halves2half2(a, __float2half(f));
659 #endif
660 }
661 
662 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pselect(const half2& mask,
663  const half2& a,
664  const half2& b) {
665  half mask_low = __low2half(mask);
666  half mask_high = __high2half(mask);
667  half result_low = mask_low == half(0) ? __low2half(b) : __low2half(a);
668  half result_high = mask_high == half(0) ? __high2half(b) : __high2half(a);
669  return __halves2half2(result_low, result_high);
670 }
671 
672 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pcmp_eq(const half2& a,
673  const half2& b) {
674  half true_half = half_impl::raw_uint16_to_half(0xffffu);
675  half false_half = half_impl::raw_uint16_to_half(0x0000u);
676  half a1 = __low2half(a);
677  half a2 = __high2half(a);
678  half b1 = __low2half(b);
679  half b2 = __high2half(b);
680  half eq1 = __half2float(a1) == __half2float(b1) ? true_half : false_half;
681  half eq2 = __half2float(a2) == __half2float(b2) ? true_half : false_half;
682  return __halves2half2(eq1, eq2);
683 }
684 
685 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pcmp_lt(const half2& a,
686  const half2& b) {
687  half true_half = half_impl::raw_uint16_to_half(0xffffu);
688  half false_half = half_impl::raw_uint16_to_half(0x0000u);
689  half a1 = __low2half(a);
690  half a2 = __high2half(a);
691  half b1 = __low2half(b);
692  half b2 = __high2half(b);
693  half eq1 = __half2float(a1) < __half2float(b1) ? true_half : false_half;
694  half eq2 = __half2float(a2) < __half2float(b2) ? true_half : false_half;
695  return __halves2half2(eq1, eq2);
696 }
697 
698 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pcmp_le(const half2& a,
699  const half2& b) {
700  half true_half = half_impl::raw_uint16_to_half(0xffffu);
701  half false_half = half_impl::raw_uint16_to_half(0x0000u);
702  half a1 = __low2half(a);
703  half a2 = __high2half(a);
704  half b1 = __low2half(b);
705  half b2 = __high2half(b);
706  half eq1 = __half2float(a1) <= __half2float(b1) ? true_half : false_half;
707  half eq2 = __half2float(a2) <= __half2float(b2) ? true_half : false_half;
708  return __halves2half2(eq1, eq2);
709 }
710 
711 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pand(const half2& a,
712  const half2& b) {
713  half a1 = __low2half(a);
714  half a2 = __high2half(a);
715  half b1 = __low2half(b);
716  half b2 = __high2half(b);
717  half result1 = half_impl::raw_uint16_to_half(a1.x & b1.x);
718  half result2 = half_impl::raw_uint16_to_half(a2.x & b2.x);
719  return __halves2half2(result1, result2);
720 }
721 
722 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 por(const half2& a,
723  const half2& b) {
724  half a1 = __low2half(a);
725  half a2 = __high2half(a);
726  half b1 = __low2half(b);
727  half b2 = __high2half(b);
728  half result1 = half_impl::raw_uint16_to_half(a1.x | b1.x);
729  half result2 = half_impl::raw_uint16_to_half(a2.x | b2.x);
730  return __halves2half2(result1, result2);
731 }
732 
733 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pxor(const half2& a,
734  const half2& b) {
735  half a1 = __low2half(a);
736  half a2 = __high2half(a);
737  half b1 = __low2half(b);
738  half b2 = __high2half(b);
739  half result1 = half_impl::raw_uint16_to_half(a1.x ^ b1.x);
740  half result2 = half_impl::raw_uint16_to_half(a2.x ^ b2.x);
741  return __halves2half2(result1, result2);
742 }
743 
744 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pandnot(const half2& a,
745  const half2& b) {
746  half a1 = __low2half(a);
747  half a2 = __high2half(a);
748  half b1 = __low2half(b);
749  half b2 = __high2half(b);
750  half result1 = half_impl::raw_uint16_to_half(a1.x & ~b1.x);
751  half result2 = half_impl::raw_uint16_to_half(a2.x & ~b2.x);
752  return __halves2half2(result1, result2);
753 }
754 
755 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 padd(const half2& a,
756  const half2& b) {
757 #if defined(EIGEN_GPU_HAS_FP16_ARITHMETIC)
758  return __hadd2(a, b);
759 #else
760  float a1 = __low2float(a);
761  float a2 = __high2float(a);
762  float b1 = __low2float(b);
763  float b2 = __high2float(b);
764  float r1 = a1 + b1;
765  float r2 = a2 + b2;
766  return __floats2half2_rn(r1, r2);
767 #endif
768 }
769 
770 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 psub(const half2& a,
771  const half2& b) {
772 #if defined(EIGEN_GPU_HAS_FP16_ARITHMETIC)
773  return __hsub2(a, b);
774 #else
775  float a1 = __low2float(a);
776  float a2 = __high2float(a);
777  float b1 = __low2float(b);
778  float b2 = __high2float(b);
779  float r1 = a1 - b1;
780  float r2 = a2 - b2;
781  return __floats2half2_rn(r1, r2);
782 #endif
783 }
784 
785 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pnegate(const half2& a) {
786 #if defined(EIGEN_GPU_HAS_FP16_ARITHMETIC)
787  return __hneg2(a);
788 #else
789  float a1 = __low2float(a);
790  float a2 = __high2float(a);
791  return __floats2half2_rn(-a1, -a2);
792 #endif
793 }
794 
795 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pconj(const half2& a) { return a; }
796 
797 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pmul(const half2& a,
798  const half2& b) {
799 #if defined(EIGEN_GPU_HAS_FP16_ARITHMETIC)
800  return __hmul2(a, b);
801 #else
802  float a1 = __low2float(a);
803  float a2 = __high2float(a);
804  float b1 = __low2float(b);
805  float b2 = __high2float(b);
806  float r1 = a1 * b1;
807  float r2 = a2 * b2;
808  return __floats2half2_rn(r1, r2);
809 #endif
810 }
811 
812 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pmadd(const half2& a,
813  const half2& b,
814  const half2& c) {
815 #if defined(EIGEN_GPU_HAS_FP16_ARITHMETIC)
816  return __hfma2(a, b, c);
817 #else
818  float a1 = __low2float(a);
819  float a2 = __high2float(a);
820  float b1 = __low2float(b);
821  float b2 = __high2float(b);
822  float c1 = __low2float(c);
823  float c2 = __high2float(c);
824  float r1 = a1 * b1 + c1;
825  float r2 = a2 * b2 + c2;
826  return __floats2half2_rn(r1, r2);
827 #endif
828 }
829 
830 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pdiv(const half2& a,
831  const half2& b) {
832 #if defined(EIGEN_GPU_HAS_FP16_ARITHMETIC)
833  return __h2div(a, b);
834 #else
835  float a1 = __low2float(a);
836  float a2 = __high2float(a);
837  float b1 = __low2float(b);
838  float b2 = __high2float(b);
839  float r1 = a1 / b1;
840  float r2 = a2 / b2;
841  return __floats2half2_rn(r1, r2);
842 #endif
843 }
844 
845 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pmin(const half2& a,
846  const half2& b) {
847  float a1 = __low2float(a);
848  float a2 = __high2float(a);
849  float b1 = __low2float(b);
850  float b2 = __high2float(b);
851  __half r1 = a1 < b1 ? __low2half(a) : __low2half(b);
852  __half r2 = a2 < b2 ? __high2half(a) : __high2half(b);
853  return __halves2half2(r1, r2);
854 }
855 
856 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pmax(const half2& a,
857  const half2& b) {
858  float a1 = __low2float(a);
859  float a2 = __high2float(a);
860  float b1 = __low2float(b);
861  float b2 = __high2float(b);
862  __half r1 = a1 > b1 ? __low2half(a) : __low2half(b);
863  __half r2 = a2 > b2 ? __high2half(a) : __high2half(b);
864  return __halves2half2(r1, r2);
865 }
866 
867 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::half predux(const half2& a) {
868 #if defined(EIGEN_GPU_HAS_FP16_ARITHMETIC)
869  return __hadd(__low2half(a), __high2half(a));
870 #else
871  float a1 = __low2float(a);
872  float a2 = __high2float(a);
873  return Eigen::half(__float2half(a1 + a2));
874 #endif
875 }
876 
877 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::half predux_max(const half2& a) {
878 #if defined(EIGEN_GPU_HAS_FP16_ARITHMETIC)
879  __half first = __low2half(a);
880  __half second = __high2half(a);
881  return __hgt(first, second) ? first : second;
882 #else
883  float a1 = __low2float(a);
884  float a2 = __high2float(a);
885  return a1 > a2 ? __low2half(a) : __high2half(a);
886 #endif
887 }
888 
889 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::half predux_min(const half2& a) {
890 #if defined(EIGEN_GPU_HAS_FP16_ARITHMETIC)
891  __half first = __low2half(a);
892  __half second = __high2half(a);
893  return __hlt(first, second) ? first : second;
894 #else
895  float a1 = __low2float(a);
896  float a2 = __high2float(a);
897  return a1 < a2 ? __low2half(a) : __high2half(a);
898 #endif
899 }
900 
901 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::half predux_mul(const half2& a) {
902 #if defined(EIGEN_GPU_HAS_FP16_ARITHMETIC)
903  return __hmul(__low2half(a), __high2half(a));
904 #else
905  float a1 = __low2float(a);
906  float a2 = __high2float(a);
907  return Eigen::half(__float2half(a1 * a2));
908 #endif
909 }
910 
911 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 plog1p(const half2& a) {
912  float a1 = __low2float(a);
913  float a2 = __high2float(a);
914  float r1 = log1pf(a1);
915  float r2 = log1pf(a2);
916  return __floats2half2_rn(r1, r2);
917 }
918 
919 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pexpm1(const half2& a) {
920  float a1 = __low2float(a);
921  float a2 = __high2float(a);
922  float r1 = expm1f(a1);
923  float r2 = expm1f(a2);
924  return __floats2half2_rn(r1, r2);
925 }
926 
927 #if (EIGEN_CUDA_SDK_VER >= 80000 && defined(EIGEN_CUDA_HAS_FP16_ARITHMETIC)) || \
928  defined(EIGEN_HIP_DEVICE_COMPILE)
929 
930 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
931 half2 plog(const half2& a) {
932  return h2log(a);
933 }
934 
935  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
936 half2 pexp(const half2& a) {
937  return h2exp(a);
938 }
939 
940  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
941 half2 psqrt(const half2& a) {
942  return h2sqrt(a);
943 }
944 
945  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
946 half2 prsqrt(const half2& a) {
947  return h2rsqrt(a);
948 }
949 
950 #else
951 
952 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 plog(const half2& a) {
953  float a1 = __low2float(a);
954  float a2 = __high2float(a);
955  float r1 = logf(a1);
956  float r2 = logf(a2);
957  return __floats2half2_rn(r1, r2);
958 }
959 
960 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pexp(const half2& a) {
961  float a1 = __low2float(a);
962  float a2 = __high2float(a);
963  float r1 = expf(a1);
964  float r2 = expf(a2);
965  return __floats2half2_rn(r1, r2);
966 }
967 
968 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 psqrt(const half2& a) {
969  float a1 = __low2float(a);
970  float a2 = __high2float(a);
971  float r1 = sqrtf(a1);
972  float r2 = sqrtf(a2);
973  return __floats2half2_rn(r1, r2);
974 }
975 
976 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 prsqrt(const half2& a) {
977  float a1 = __low2float(a);
978  float a2 = __high2float(a);
979  float r1 = rsqrtf(a1);
980  float r2 = rsqrtf(a2);
981  return __floats2half2_rn(r1, r2);
982 }
983 #endif
984 } // namespace
985 
986 template <>
987 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2
988 pload<Packet4h2>(const Eigen::half* from) {
989  return *reinterpret_cast<const Packet4h2*>(from);
990 }
991 
992 // unaligned load;
993 template <>
994 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2
995 ploadu<Packet4h2>(const Eigen::half* from) {
996  Packet4h2 r;
997  half2* p_alias = reinterpret_cast<half2*>(&r);
998  p_alias[0] = ploadu(from + 0);
999  p_alias[1] = ploadu(from + 2);
1000  p_alias[2] = ploadu(from + 4);
1001  p_alias[3] = ploadu(from + 6);
1002  return r;
1003 }
1004 
1005 template <>
1006 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2
1007 ploaddup<Packet4h2>(const Eigen::half* from) {
1008  Packet4h2 r;
1009  half2* p_alias = reinterpret_cast<half2*>(&r);
1010  p_alias[0] = ploaddup(from + 0);
1011  p_alias[1] = ploaddup(from + 1);
1012  p_alias[2] = ploaddup(from + 2);
1013  p_alias[3] = ploaddup(from + 3);
1014  return r;
1015 }
1016 
1017 template <>
1018 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pstore<Eigen::half>(
1019  Eigen::half* to, const Packet4h2& from) {
1020  *reinterpret_cast<Packet4h2*>(to) = from;
1021 }
1022 
1023 template <>
1024 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pstoreu<Eigen::half>(
1025  Eigen::half* to, const Packet4h2& from) {
1026  const half2* from_alias = reinterpret_cast<const half2*>(&from);
1027  pstoreu(to + 0,from_alias[0]);
1028  pstoreu(to + 2,from_alias[1]);
1029  pstoreu(to + 4,from_alias[2]);
1030  pstoreu(to + 6,from_alias[3]);
1031 }
1032 
1033 template <>
1035 ploadt_ro<Packet4h2, Aligned>(const Eigen::half* from) {
1036 #if defined(EIGEN_GPU_HAS_LDG)
1037  Packet4h2 r;
1038  r = __ldg(reinterpret_cast<const Packet4h2*>(from));
1039  return r;
1040 #else
1041  Packet4h2 r;
1042  half2* r_alias = reinterpret_cast<half2*>(&r);
1043  r_alias[0] = ploadt_ro_aligned(from + 0);
1044  r_alias[1] = ploadt_ro_aligned(from + 2);
1045  r_alias[2] = ploadt_ro_aligned(from + 4);
1046  r_alias[3] = ploadt_ro_aligned(from + 6);
1047  return r;
1048 #endif
1049 }
1050 
1051 template <>
1053 ploadt_ro<Packet4h2, Unaligned>(const Eigen::half* from) {
1054  Packet4h2 r;
1055  half2* r_alias = reinterpret_cast<half2*>(&r);
1056  r_alias[0] = ploadt_ro_unaligned(from + 0);
1057  r_alias[1] = ploadt_ro_unaligned(from + 2);
1058  r_alias[2] = ploadt_ro_unaligned(from + 4);
1059  r_alias[3] = ploadt_ro_unaligned(from + 6);
1060  return r;
1061 }
1062 
1063 template <>
1064 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2
1065 pgather<Eigen::half, Packet4h2>(const Eigen::half* from, Index stride) {
1066  Packet4h2 r;
1067  half2* p_alias = reinterpret_cast<half2*>(&r);
1068  p_alias[0] = __halves2half2(from[0 * stride], from[1 * stride]);
1069  p_alias[1] = __halves2half2(from[2 * stride], from[3 * stride]);
1070  p_alias[2] = __halves2half2(from[4 * stride], from[5 * stride]);
1071  p_alias[3] = __halves2half2(from[6 * stride], from[7 * stride]);
1072  return r;
1073 }
1074 
1075 template <>
1076 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<Eigen::half, Packet4h2>(
1077  Eigen::half* to, const Packet4h2& from, Index stride) {
1078  const half2* from_alias = reinterpret_cast<const half2*>(&from);
1079  pscatter(to + stride * 0, from_alias[0], stride);
1080  pscatter(to + stride * 2, from_alias[1], stride);
1081  pscatter(to + stride * 4, from_alias[2], stride);
1082  pscatter(to + stride * 6, from_alias[3], stride);
1083 }
1084 
1085 template <>
1086 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::half pfirst<Packet4h2>(
1087  const Packet4h2& a) {
1088  return pfirst(*(reinterpret_cast<const half2*>(&a)));
1089 }
1090 
1091 template <>
1092 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 pabs<Packet4h2>(
1093  const Packet4h2& a) {
1094  Packet4h2 r;
1095  half2* p_alias = reinterpret_cast<half2*>(&r);
1096  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1097  p_alias[0] = pabs(a_alias[0]);
1098  p_alias[1] = pabs(a_alias[1]);
1099  p_alias[2] = pabs(a_alias[2]);
1100  p_alias[3] = pabs(a_alias[3]);
1101  return r;
1102 }
1103 
1104 template <>
1105 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 ptrue<Packet4h2>(
1106  const Packet4h2& /*a*/) {
1107  half true_half = half_impl::raw_uint16_to_half(0xffffu);
1108  return pset1<Packet4h2>(true_half);
1109 }
1110 
1111 template <>
1112 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 pzero<Packet4h2>(const Packet4h2& /*a*/) {
1113  half false_half = half_impl::raw_uint16_to_half(0x0000u);
1114  return pset1<Packet4h2>(false_half);
1115 }
1116 
1117 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose_double(
1118  double* d_row0, double* d_row1, double* d_row2, double* d_row3,
1119  double* d_row4, double* d_row5, double* d_row6, double* d_row7) {
1120  double d_tmp;
1121  d_tmp = d_row0[1];
1122  d_row0[1] = d_row4[0];
1123  d_row4[0] = d_tmp;
1124 
1125  d_tmp = d_row1[1];
1126  d_row1[1] = d_row5[0];
1127  d_row5[0] = d_tmp;
1128 
1129  d_tmp = d_row2[1];
1130  d_row2[1] = d_row6[0];
1131  d_row6[0] = d_tmp;
1132 
1133  d_tmp = d_row3[1];
1134  d_row3[1] = d_row7[0];
1135  d_row7[0] = d_tmp;
1136 }
1137 
1138 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose_half2(
1139  half2* f_row0, half2* f_row1, half2* f_row2, half2* f_row3) {
1140  half2 f_tmp;
1141  f_tmp = f_row0[1];
1142  f_row0[1] = f_row2[0];
1143  f_row2[0] = f_tmp;
1144 
1145  f_tmp = f_row1[1];
1146  f_row1[1] = f_row3[0];
1147  f_row3[0] = f_tmp;
1148 }
1149 
1150 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void
1151 ptranspose_half(half2& f0, half2& f1) {
1152  __half a1 = __low2half(f0);
1153  __half a2 = __high2half(f0);
1154  __half b1 = __low2half(f1);
1155  __half b2 = __high2half(f1);
1156  f0 = __halves2half2(a1, b1);
1157  f1 = __halves2half2(a2, b2);
1158 }
1159 
1160 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void
1161 ptranspose(PacketBlock<Packet4h2,8>& kernel) {
1162  double* d_row0 = reinterpret_cast<double*>(&kernel.packet[0]);
1163  double* d_row1 = reinterpret_cast<double*>(&kernel.packet[1]);
1164  double* d_row2 = reinterpret_cast<double*>(&kernel.packet[2]);
1165  double* d_row3 = reinterpret_cast<double*>(&kernel.packet[3]);
1166  double* d_row4 = reinterpret_cast<double*>(&kernel.packet[4]);
1167  double* d_row5 = reinterpret_cast<double*>(&kernel.packet[5]);
1168  double* d_row6 = reinterpret_cast<double*>(&kernel.packet[6]);
1169  double* d_row7 = reinterpret_cast<double*>(&kernel.packet[7]);
1170  ptranspose_double(d_row0, d_row1, d_row2, d_row3,
1171  d_row4, d_row5, d_row6, d_row7);
1172 
1173 
1174  half2* f_row0 = reinterpret_cast<half2*>(d_row0);
1175  half2* f_row1 = reinterpret_cast<half2*>(d_row1);
1176  half2* f_row2 = reinterpret_cast<half2*>(d_row2);
1177  half2* f_row3 = reinterpret_cast<half2*>(d_row3);
1178  ptranspose_half2(f_row0, f_row1, f_row2, f_row3);
1179  ptranspose_half(f_row0[0], f_row1[0]);
1180  ptranspose_half(f_row0[1], f_row1[1]);
1181  ptranspose_half(f_row2[0], f_row3[0]);
1182  ptranspose_half(f_row2[1], f_row3[1]);
1183 
1184  f_row0 = reinterpret_cast<half2*>(d_row0 + 1);
1185  f_row1 = reinterpret_cast<half2*>(d_row1 + 1);
1186  f_row2 = reinterpret_cast<half2*>(d_row2 + 1);
1187  f_row3 = reinterpret_cast<half2*>(d_row3 + 1);
1188  ptranspose_half2(f_row0, f_row1, f_row2, f_row3);
1189  ptranspose_half(f_row0[0], f_row1[0]);
1190  ptranspose_half(f_row0[1], f_row1[1]);
1191  ptranspose_half(f_row2[0], f_row3[0]);
1192  ptranspose_half(f_row2[1], f_row3[1]);
1193 
1194  f_row0 = reinterpret_cast<half2*>(d_row4);
1195  f_row1 = reinterpret_cast<half2*>(d_row5);
1196  f_row2 = reinterpret_cast<half2*>(d_row6);
1197  f_row3 = reinterpret_cast<half2*>(d_row7);
1198  ptranspose_half2(f_row0, f_row1, f_row2, f_row3);
1199  ptranspose_half(f_row0[0], f_row1[0]);
1200  ptranspose_half(f_row0[1], f_row1[1]);
1201  ptranspose_half(f_row2[0], f_row3[0]);
1202  ptranspose_half(f_row2[1], f_row3[1]);
1203 
1204  f_row0 = reinterpret_cast<half2*>(d_row4 + 1);
1205  f_row1 = reinterpret_cast<half2*>(d_row5 + 1);
1206  f_row2 = reinterpret_cast<half2*>(d_row6 + 1);
1207  f_row3 = reinterpret_cast<half2*>(d_row7 + 1);
1208  ptranspose_half2(f_row0, f_row1, f_row2, f_row3);
1209  ptranspose_half(f_row0[0], f_row1[0]);
1210  ptranspose_half(f_row0[1], f_row1[1]);
1211  ptranspose_half(f_row2[0], f_row3[0]);
1212  ptranspose_half(f_row2[1], f_row3[1]);
1213 
1214 }
1215 
1216 template <>
1217 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2
1218 plset<Packet4h2>(const Eigen::half& a) {
1219 #if defined(EIGEN_HIP_DEVICE_COMPILE)
1220 
1221  Packet4h2 r;
1222  half2* p_alias = reinterpret_cast<half2*>(&r);
1223  p_alias[0] = __halves2half2(a, __hadd(a, __float2half(1.0f)));
1224  p_alias[1] = __halves2half2(__hadd(a, __float2half(2.0f)),
1225  __hadd(a, __float2half(3.0f)));
1226  p_alias[2] = __halves2half2(__hadd(a, __float2half(4.0f)),
1227  __hadd(a, __float2half(5.0f)));
1228  p_alias[3] = __halves2half2(__hadd(a, __float2half(6.0f)),
1229  __hadd(a, __float2half(7.0f)));
1230  return r;
1231 #elif defined(EIGEN_CUDA_HAS_FP16_ARITHMETIC)
1232  Packet4h2 r;
1233  half2* r_alias = reinterpret_cast<half2*>(&r);
1234 
1235  half2 b = pset1<half2>(a);
1236  half2 c;
1237  half2 half_offset0 = __halves2half2(__float2half(0.0f),__float2half(2.0f));
1238  half2 half_offset1 = __halves2half2(__float2half(4.0f),__float2half(6.0f));
1239 
1240  c = __hadd2(b, half_offset0);
1241  r_alias[0] = plset(__low2half(c));
1242  r_alias[1] = plset(__high2half(c));
1243 
1244  c = __hadd2(b, half_offset1);
1245  r_alias[2] = plset(__low2half(c));
1246  r_alias[3] = plset(__high2half(c));
1247 
1248  return r;
1249 
1250 #else
1251  float f = __half2float(a);
1252  Packet4h2 r;
1253  half2* p_alias = reinterpret_cast<half2*>(&r);
1254  p_alias[0] = __halves2half2(a, __float2half(f + 1.0f));
1255  p_alias[1] = __halves2half2(__float2half(f + 2.0f), __float2half(f + 3.0f));
1256  p_alias[2] = __halves2half2(__float2half(f + 4.0f), __float2half(f + 5.0f));
1257  p_alias[3] = __halves2half2(__float2half(f + 6.0f), __float2half(f + 7.0f));
1258  return r;
1259 #endif
1260 }
1261 
1262 template <>
1263 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2
1264 pselect<Packet4h2>(const Packet4h2& mask, const Packet4h2& a,
1265  const Packet4h2& b) {
1266  Packet4h2 r;
1267  half2* r_alias = reinterpret_cast<half2*>(&r);
1268  const half2* mask_alias = reinterpret_cast<const half2*>(&mask);
1269  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1270  const half2* b_alias = reinterpret_cast<const half2*>(&b);
1271  r_alias[0] = pselect(mask_alias[0], a_alias[0], b_alias[0]);
1272  r_alias[1] = pselect(mask_alias[1], a_alias[1], b_alias[1]);
1273  r_alias[2] = pselect(mask_alias[2], a_alias[2], b_alias[2]);
1274  r_alias[3] = pselect(mask_alias[3], a_alias[3], b_alias[3]);
1275  return r;
1276 }
1277 
1278 template <>
1279 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2
1280 pcmp_eq<Packet4h2>(const Packet4h2& a, const Packet4h2& b) {
1281  Packet4h2 r;
1282  half2* r_alias = reinterpret_cast<half2*>(&r);
1283  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1284  const half2* b_alias = reinterpret_cast<const half2*>(&b);
1285  r_alias[0] = pcmp_eq(a_alias[0], b_alias[0]);
1286  r_alias[1] = pcmp_eq(a_alias[1], b_alias[1]);
1287  r_alias[2] = pcmp_eq(a_alias[2], b_alias[2]);
1288  r_alias[3] = pcmp_eq(a_alias[3], b_alias[3]);
1289  return r;
1290 }
1291 
1292 template <>
1293 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2
1294 pcmp_lt<Packet4h2>(const Packet4h2& a, const Packet4h2& b) {
1295  Packet4h2 r;
1296  half2* r_alias = reinterpret_cast<half2*>(&r);
1297  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1298  const half2* b_alias = reinterpret_cast<const half2*>(&b);
1299  r_alias[0] = pcmp_lt(a_alias[0], b_alias[0]);
1300  r_alias[1] = pcmp_lt(a_alias[1], b_alias[1]);
1301  r_alias[2] = pcmp_lt(a_alias[2], b_alias[2]);
1302  r_alias[3] = pcmp_lt(a_alias[3], b_alias[3]);
1303  return r;
1304 }
1305 
1306 template <>
1307 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2
1308 pcmp_le<Packet4h2>(const Packet4h2& a, const Packet4h2& b) {
1309  Packet4h2 r;
1310  half2* r_alias = reinterpret_cast<half2*>(&r);
1311  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1312  const half2* b_alias = reinterpret_cast<const half2*>(&b);
1313  r_alias[0] = pcmp_le(a_alias[0], b_alias[0]);
1314  r_alias[1] = pcmp_le(a_alias[1], b_alias[1]);
1315  r_alias[2] = pcmp_le(a_alias[2], b_alias[2]);
1316  r_alias[3] = pcmp_le(a_alias[3], b_alias[3]);
1317  return r;
1318 }
1319 
1320 template <>
1321 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 pand<Packet4h2>(
1322  const Packet4h2& a, const Packet4h2& b) {
1323  Packet4h2 r;
1324  half2* r_alias = reinterpret_cast<half2*>(&r);
1325  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1326  const half2* b_alias = reinterpret_cast<const half2*>(&b);
1327  r_alias[0] = pand(a_alias[0], b_alias[0]);
1328  r_alias[1] = pand(a_alias[1], b_alias[1]);
1329  r_alias[2] = pand(a_alias[2], b_alias[2]);
1330  r_alias[3] = pand(a_alias[3], b_alias[3]);
1331  return r;
1332 }
1333 
1334 template <>
1335 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 por<Packet4h2>(
1336  const Packet4h2& a, const Packet4h2& b) {
1337  Packet4h2 r;
1338  half2* r_alias = reinterpret_cast<half2*>(&r);
1339  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1340  const half2* b_alias = reinterpret_cast<const half2*>(&b);
1341  r_alias[0] = por(a_alias[0], b_alias[0]);
1342  r_alias[1] = por(a_alias[1], b_alias[1]);
1343  r_alias[2] = por(a_alias[2], b_alias[2]);
1344  r_alias[3] = por(a_alias[3], b_alias[3]);
1345  return r;
1346 }
1347 
1348 template <>
1349 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 pxor<Packet4h2>(
1350  const Packet4h2& a, const Packet4h2& b) {
1351  Packet4h2 r;
1352  half2* r_alias = reinterpret_cast<half2*>(&r);
1353  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1354  const half2* b_alias = reinterpret_cast<const half2*>(&b);
1355  r_alias[0] = pxor(a_alias[0], b_alias[0]);
1356  r_alias[1] = pxor(a_alias[1], b_alias[1]);
1357  r_alias[2] = pxor(a_alias[2], b_alias[2]);
1358  r_alias[3] = pxor(a_alias[3], b_alias[3]);
1359  return r;
1360 }
1361 
1362 template <>
1363 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2
1364 pandnot<Packet4h2>(const Packet4h2& a, const Packet4h2& b) {
1365  Packet4h2 r;
1366  half2* r_alias = reinterpret_cast<half2*>(&r);
1367  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1368  const half2* b_alias = reinterpret_cast<const half2*>(&b);
1369  r_alias[0] = pandnot(a_alias[0], b_alias[0]);
1370  r_alias[1] = pandnot(a_alias[1], b_alias[1]);
1371  r_alias[2] = pandnot(a_alias[2], b_alias[2]);
1372  r_alias[3] = pandnot(a_alias[3], b_alias[3]);
1373  return r;
1374 }
1375 
1376 template <>
1377 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 padd<Packet4h2>(
1378  const Packet4h2& a, const Packet4h2& b) {
1379  Packet4h2 r;
1380  half2* r_alias = reinterpret_cast<half2*>(&r);
1381  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1382  const half2* b_alias = reinterpret_cast<const half2*>(&b);
1383  r_alias[0] = padd(a_alias[0], b_alias[0]);
1384  r_alias[1] = padd(a_alias[1], b_alias[1]);
1385  r_alias[2] = padd(a_alias[2], b_alias[2]);
1386  r_alias[3] = padd(a_alias[3], b_alias[3]);
1387  return r;
1388 }
1389 
1390 template <>
1391 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 psub<Packet4h2>(
1392  const Packet4h2& a, const Packet4h2& b) {
1393  Packet4h2 r;
1394  half2* r_alias = reinterpret_cast<half2*>(&r);
1395  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1396  const half2* b_alias = reinterpret_cast<const half2*>(&b);
1397  r_alias[0] = psub(a_alias[0], b_alias[0]);
1398  r_alias[1] = psub(a_alias[1], b_alias[1]);
1399  r_alias[2] = psub(a_alias[2], b_alias[2]);
1400  r_alias[3] = psub(a_alias[3], b_alias[3]);
1401  return r;
1402 }
1403 
1404 template <>
1405 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 pnegate(const Packet4h2& a) {
1406  Packet4h2 r;
1407  half2* r_alias = reinterpret_cast<half2*>(&r);
1408  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1409  r_alias[0] = pnegate(a_alias[0]);
1410  r_alias[1] = pnegate(a_alias[1]);
1411  r_alias[2] = pnegate(a_alias[2]);
1412  r_alias[3] = pnegate(a_alias[3]);
1413  return r;
1414 }
1415 
1416 template <>
1417 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 pconj(const Packet4h2& a) {
1418  return a;
1419 }
1420 
1421 template <>
1422 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 pmul<Packet4h2>(
1423  const Packet4h2& a, const Packet4h2& b) {
1424  Packet4h2 r;
1425  half2* r_alias = reinterpret_cast<half2*>(&r);
1426  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1427  const half2* b_alias = reinterpret_cast<const half2*>(&b);
1428  r_alias[0] = pmul(a_alias[0], b_alias[0]);
1429  r_alias[1] = pmul(a_alias[1], b_alias[1]);
1430  r_alias[2] = pmul(a_alias[2], b_alias[2]);
1431  r_alias[3] = pmul(a_alias[3], b_alias[3]);
1432  return r;
1433 }
1434 
1435 template <>
1436 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 pmadd<Packet4h2>(
1437  const Packet4h2& a, const Packet4h2& b, const Packet4h2& c) {
1438  Packet4h2 r;
1439  half2* r_alias = reinterpret_cast<half2*>(&r);
1440  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1441  const half2* b_alias = reinterpret_cast<const half2*>(&b);
1442  const half2* c_alias = reinterpret_cast<const half2*>(&c);
1443  r_alias[0] = pmadd(a_alias[0], b_alias[0], c_alias[0]);
1444  r_alias[1] = pmadd(a_alias[1], b_alias[1], c_alias[1]);
1445  r_alias[2] = pmadd(a_alias[2], b_alias[2], c_alias[2]);
1446  r_alias[3] = pmadd(a_alias[3], b_alias[3], c_alias[3]);
1447  return r;
1448 }
1449 
1450 template <>
1451 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 pdiv<Packet4h2>(
1452  const Packet4h2& a, const Packet4h2& b) {
1453  Packet4h2 r;
1454  half2* r_alias = reinterpret_cast<half2*>(&r);
1455  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1456  const half2* b_alias = reinterpret_cast<const half2*>(&b);
1457  r_alias[0] = pdiv(a_alias[0], b_alias[0]);
1458  r_alias[1] = pdiv(a_alias[1], b_alias[1]);
1459  r_alias[2] = pdiv(a_alias[2], b_alias[2]);
1460  r_alias[3] = pdiv(a_alias[3], b_alias[3]);
1461  return r;
1462 }
1463 
1464 template <>
1465 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 pmin<Packet4h2>(
1466  const Packet4h2& a, const Packet4h2& b) {
1467  Packet4h2 r;
1468  half2* r_alias = reinterpret_cast<half2*>(&r);
1469  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1470  const half2* b_alias = reinterpret_cast<const half2*>(&b);
1471  r_alias[0] = pmin(a_alias[0], b_alias[0]);
1472  r_alias[1] = pmin(a_alias[1], b_alias[1]);
1473  r_alias[2] = pmin(a_alias[2], b_alias[2]);
1474  r_alias[3] = pmin(a_alias[3], b_alias[3]);
1475  return r;
1476 }
1477 
1478 template <>
1479 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 pmax<Packet4h2>(
1480  const Packet4h2& a, const Packet4h2& b) {
1481  Packet4h2 r;
1482  half2* r_alias = reinterpret_cast<half2*>(&r);
1483  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1484  const half2* b_alias = reinterpret_cast<const half2*>(&b);
1485  r_alias[0] = pmax(a_alias[0], b_alias[0]);
1486  r_alias[1] = pmax(a_alias[1], b_alias[1]);
1487  r_alias[2] = pmax(a_alias[2], b_alias[2]);
1488  r_alias[3] = pmax(a_alias[3], b_alias[3]);
1489  return r;
1490 }
1491 
1492 template <>
1493 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::half predux<Packet4h2>(
1494  const Packet4h2& a) {
1495  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1496 
1497  return predux(a_alias[0]) + predux(a_alias[1]) +
1498  predux(a_alias[2]) + predux(a_alias[3]);
1499 }
1500 
1501 template <>
1502 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::half predux_max<Packet4h2>(
1503  const Packet4h2& a) {
1504  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1505  half2 m0 = __halves2half2(predux_max(a_alias[0]),
1506  predux_max(a_alias[1]));
1507  half2 m1 = __halves2half2(predux_max(a_alias[2]),
1508  predux_max(a_alias[3]));
1509  __half first = predux_max(m0);
1510  __half second = predux_max(m1);
1511 #if defined(EIGEN_CUDA_HAS_FP16_ARITHMETIC)
1512  return (__hgt(first, second) ? first : second);
1513 #else
1514  float ffirst = __half2float(first);
1515  float fsecond = __half2float(second);
1516  return (ffirst > fsecond)? first: second;
1517 #endif
1518 }
1519 
1520 template <>
1521 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::half predux_min<Packet4h2>(
1522  const Packet4h2& a) {
1523  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1524  half2 m0 = __halves2half2(predux_min(a_alias[0]),
1525  predux_min(a_alias[1]));
1526  half2 m1 = __halves2half2(predux_min(a_alias[2]),
1527  predux_min(a_alias[3]));
1528  __half first = predux_min(m0);
1529  __half second = predux_min(m1);
1530 #if defined(EIGEN_CUDA_HAS_FP16_ARITHMETIC)
1531  return (__hlt(first, second) ? first : second);
1532 #else
1533  float ffirst = __half2float(first);
1534  float fsecond = __half2float(second);
1535  return (ffirst < fsecond)? first: second;
1536 #endif
1537 }
1538 
1539 // likely overflow/underflow
1540 template <>
1541 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::half predux_mul<Packet4h2>(
1542  const Packet4h2& a) {
1543  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1544  return predux_mul(pmul(pmul(a_alias[0], a_alias[1]),
1545  pmul(a_alias[2], a_alias[3])));
1546 }
1547 
1548 template <>
1549 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2
1550 plog1p<Packet4h2>(const Packet4h2& a) {
1551  Packet4h2 r;
1552  half2* r_alias = reinterpret_cast<half2*>(&r);
1553  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1554  r_alias[0] = plog1p(a_alias[0]);
1555  r_alias[1] = plog1p(a_alias[1]);
1556  r_alias[2] = plog1p(a_alias[2]);
1557  r_alias[3] = plog1p(a_alias[3]);
1558  return r;
1559 }
1560 
1561 template <>
1562 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2
1563 pexpm1<Packet4h2>(const Packet4h2& a) {
1564  Packet4h2 r;
1565  half2* r_alias = reinterpret_cast<half2*>(&r);
1566  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1567  r_alias[0] = pexpm1(a_alias[0]);
1568  r_alias[1] = pexpm1(a_alias[1]);
1569  r_alias[2] = pexpm1(a_alias[2]);
1570  r_alias[3] = pexpm1(a_alias[3]);
1571  return r;
1572 }
1573 
1574 template <>
1575 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 plog<Packet4h2>(const Packet4h2& a) {
1576  Packet4h2 r;
1577  half2* r_alias = reinterpret_cast<half2*>(&r);
1578  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1579  r_alias[0] = plog(a_alias[0]);
1580  r_alias[1] = plog(a_alias[1]);
1581  r_alias[2] = plog(a_alias[2]);
1582  r_alias[3] = plog(a_alias[3]);
1583  return r;
1584 }
1585 
1586 template <>
1587 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 pexp<Packet4h2>(const Packet4h2& a) {
1588  Packet4h2 r;
1589  half2* r_alias = reinterpret_cast<half2*>(&r);
1590  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1591  r_alias[0] = pexp(a_alias[0]);
1592  r_alias[1] = pexp(a_alias[1]);
1593  r_alias[2] = pexp(a_alias[2]);
1594  r_alias[3] = pexp(a_alias[3]);
1595  return r;
1596 }
1597 
1598 template <>
1599 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2 psqrt<Packet4h2>(const Packet4h2& a) {
1600  Packet4h2 r;
1601  half2* r_alias = reinterpret_cast<half2*>(&r);
1602  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1603  r_alias[0] = psqrt(a_alias[0]);
1604  r_alias[1] = psqrt(a_alias[1]);
1605  r_alias[2] = psqrt(a_alias[2]);
1606  r_alias[3] = psqrt(a_alias[3]);
1607  return r;
1608 }
1609 
1610 template <>
1611 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4h2
1612 prsqrt<Packet4h2>(const Packet4h2& a) {
1613  Packet4h2 r;
1614  half2* r_alias = reinterpret_cast<half2*>(&r);
1615  const half2* a_alias = reinterpret_cast<const half2*>(&a);
1616  r_alias[0] = prsqrt(a_alias[0]);
1617  r_alias[1] = prsqrt(a_alias[1]);
1618  r_alias[2] = prsqrt(a_alias[2]);
1619  r_alias[3] = prsqrt(a_alias[3]);
1620  return r;
1621 }
1622 
1623 // The following specialized padd, pmul, pdiv, pmin, pmax, pset1 are needed for
1624 // the implementation of GPU half reduction.
1625 template<>
1626 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 padd<half2>(const half2& a,
1627  const half2& b) {
1628 #if defined(EIGEN_GPU_HAS_FP16_ARITHMETIC)
1629  return __hadd2(a, b);
1630 #else
1631  float a1 = __low2float(a);
1632  float a2 = __high2float(a);
1633  float b1 = __low2float(b);
1634  float b2 = __high2float(b);
1635  float r1 = a1 + b1;
1636  float r2 = a2 + b2;
1637  return __floats2half2_rn(r1, r2);
1638 #endif
1639 }
1640 
1641 template<>
1642 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pmul<half2>(const half2& a,
1643  const half2& b) {
1644 #if defined(EIGEN_GPU_HAS_FP16_ARITHMETIC)
1645  return __hmul2(a, b);
1646 #else
1647  float a1 = __low2float(a);
1648  float a2 = __high2float(a);
1649  float b1 = __low2float(b);
1650  float b2 = __high2float(b);
1651  float r1 = a1 * b1;
1652  float r2 = a2 * b2;
1653  return __floats2half2_rn(r1, r2);
1654 #endif
1655 }
1656 
1657 template<>
1658 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pdiv<half2>(const half2& a,
1659  const half2& b) {
1660 #if defined(EIGEN_GPU_HAS_FP16_ARITHMETIC)
1661  return __h2div(a, b);
1662 #else
1663  float a1 = __low2float(a);
1664  float a2 = __high2float(a);
1665  float b1 = __low2float(b);
1666  float b2 = __high2float(b);
1667  float r1 = a1 / b1;
1668  float r2 = a2 / b2;
1669  return __floats2half2_rn(r1, r2);
1670 #endif
1671 }
1672 
1673 template<>
1674 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pmin<half2>(const half2& a,
1675  const half2& b) {
1676  float a1 = __low2float(a);
1677  float a2 = __high2float(a);
1678  float b1 = __low2float(b);
1679  float b2 = __high2float(b);
1680  __half r1 = a1 < b1 ? __low2half(a) : __low2half(b);
1681  __half r2 = a2 < b2 ? __high2half(a) : __high2half(b);
1682  return __halves2half2(r1, r2);
1683 }
1684 
1685 template<>
1686 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half2 pmax<half2>(const half2& a,
1687  const half2& b) {
1688  float a1 = __low2float(a);
1689  float a2 = __high2float(a);
1690  float b1 = __low2float(b);
1691  float b2 = __high2float(b);
1692  __half r1 = a1 > b1 ? __low2half(a) : __low2half(b);
1693  __half r2 = a2 > b2 ? __high2half(a) : __high2half(b);
1694  return __halves2half2(r1, r2);
1695 }
1696 
1697 #endif // (defined(EIGEN_HAS_CUDA_FP16) || defined(EIGEN_HAS_HIP_FP16)) && defined(EIGEN_GPU_COMPILE_PHASE)
1698 
1699 #undef EIGEN_GPU_HAS_LDG
1700 #undef EIGEN_CUDA_HAS_FP16_ARITHMETIC
1701 #undef EIGEN_GPU_HAS_FP16_ARITHMETIC
1702 
1703 } // end namespace internal
1704 
1705 } // end namespace Eigen
1706 
1707 
1708 #endif // EIGEN_PACKET_MATH_GPU_H
Array< int, 3, 1 > b
Array33i c
Matrix3d m1
Definition: IOFormat.cpp:2
#define EIGEN_ALWAYS_INLINE
Definition: Macros.h:836
#define EIGEN_DEVICE_FUNC
Definition: Macros.h:883
@ Aligned16
Definition: Constants.h:237
bfloat16 fmax(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:702
bfloat16 fmin(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:696
EIGEN_CONSTEXPR __half_raw raw_uint16_to_half(numext::uint16_t x)
Definition: Half.h:551
Packet pmin(const Packet &a, const Packet &b)
EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pexpm1(const Packet &a)
Packet padd(const Packet &a, const Packet &b)
Packet8f pzero(const Packet8f &)
void pstore(Scalar *to, const Packet &from)
void pstore< float >(float *to, const Packet4f &from)
unpacket_traits< Packet >::type predux(const Packet &a)
Packet8h ptrue(const Packet8h &a)
Packet ploadu(const typename unpacket_traits< Packet >::type *from)
EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog(const Packet &a)
Packet8h pandnot(const Packet8h &a, const Packet8h &b)
Packet4f pabs(const Packet4f &a)
Packet pmax(const Packet &a, const Packet &b)
Packet2cf pnegate(const Packet2cf &a)
EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pexp(const Packet &a)
Packet4f pmadd(const Packet4f &a, const Packet4f &b, const Packet4f &c)
void pstoreu(Scalar *to, const Packet &from)
Packet2cf pcmp_eq(const Packet2cf &a, const Packet2cf &b)
bfloat16 pfirst(const Packet8bf &a)
void pstoreu< double >(double *to, const Packet4d &from)
Packet4f pselect(const Packet4f &mask, const Packet4f &a, const Packet4f &b)
Packet pmul(const Packet &a, const Packet &b)
void pscatter(Scalar *to, const Packet &from, Index stride, typename unpacket_traits< Packet >::mask_t umask)
void ptranspose(PacketBlock< Packet2cf, 2 > &kernel)
Packet4f psqrt(const Packet4f &a)
Packet psub(const Packet &a, const Packet &b)
Packet pgather(const Packet &src, const Scalar *from, Index stride, typename unpacket_traits< Packet >::mask_t umask)
unpacket_traits< Packet >::type predux_mul(const Packet &a)
Packet8h pand(const Packet8h &a, const Packet8h &b)
EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog1p(const Packet &a)
void pstoreu< float >(float *to, const Packet4f &from)
EIGEN_CONSTEXPR Index first(const T &x) EIGEN_NOEXCEPT
Packet8h pxor(const Packet8h &a, const Packet8h &b)
Packet ploaddup(const typename unpacket_traits< Packet >::type *from)
Packet pdiv(const Packet &a, const Packet &b)
unpacket_traits< Packet >::type predux_max(const Packet &a)
Packet2cf pconj(const Packet2cf &a)
Packet plset(const typename unpacket_traits< Packet >::type &a)
Packet8h por(const Packet8h &a, const Packet8h &b)
Packet4i pcmp_lt(const Packet4i &a, const Packet4i &b)
Packet pload(const typename unpacket_traits< Packet >::type *from)
unpacket_traits< Packet >::type predux_min(const Packet &a)
void pstore< double >(double *to, const Packet4d &from)
Packet4f pcmp_le(const Packet4f &a, const Packet4f &b)
Packet4f prsqrt(const Packet4f &a)
: InteropHeaders
Definition: Core:139
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:82
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_floor_op< typename Derived::Scalar >, const Derived > floor(const Eigen::ArrayBase< Derived > &x)