Eigen  5.0.1
 
Loading...
Searching...
No Matches
PacketMath.h
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// SPDX-License-Identifier: MPL-2.0
10
11#ifndef EIGEN_PACKET_MATH_AVX_H
12#define EIGEN_PACKET_MATH_AVX_H
13
14// IWYU pragma: private
15#include "../../InternalHeaderCheck.h"
16
17namespace Eigen {
18
19namespace internal {
20
21#ifndef EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD
22#define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 8
23#endif
24
25#if !defined(EIGEN_VECTORIZE_AVX512) && !defined(EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS)
26#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 16
27#endif
28
29#ifdef EIGEN_VECTORIZE_FMA
30#ifndef EIGEN_HAS_SINGLE_INSTRUCTION_MADD
31#define EIGEN_HAS_SINGLE_INSTRUCTION_MADD
32#endif
33#endif
34
35typedef __m256 Packet8f;
36typedef eigen_packet_wrapper<__m256i, 0> Packet8i;
37typedef __m256d Packet4d;
38#ifndef EIGEN_VECTORIZE_AVX512FP16
39typedef eigen_packet_wrapper<__m128i, 2> Packet8h;
40#endif
41typedef eigen_packet_wrapper<__m128i, 3> Packet8bf;
42typedef eigen_packet_wrapper<__m256i, 4> Packet8ui;
43
44#ifdef EIGEN_VECTORIZE_AVX2
45// Start from 3 to be compatible with AVX512
46typedef eigen_packet_wrapper<__m256i, 3> Packet4l;
47typedef eigen_packet_wrapper<__m256i, 5> Packet4ul;
48#endif
49
50#define SIGN_MASK_I64 static_cast<int64_t>(0x8000000000000000ULL)
51
52template <>
53struct is_arithmetic<__m256> : std::true_type {};
54template <>
55struct is_arithmetic<__m256i> : std::true_type {};
56template <>
57struct is_arithmetic<__m256d> : std::true_type {};
58template <>
59struct is_arithmetic<Packet8i> : std::true_type {};
60// Note that `Packet8ui` uses the underlying type `__m256i`, which is
61// interpreted as a vector of _signed_ `int32`s, which breaks some arithmetic
62// operations used in `GenericPacketMath.h`.
63template <>
64struct is_arithmetic<Packet8ui> : std::false_type {};
65#ifndef EIGEN_VECTORIZE_AVX512FP16
66template <>
67struct is_arithmetic<Packet8h> : std::true_type {};
68#endif
69template <>
70struct is_arithmetic<Packet8bf> : std::true_type {};
71#ifdef EIGEN_VECTORIZE_AVX2
72template <>
73struct is_arithmetic<Packet4l> : std::true_type {};
74// Note that `Packet4ul` uses the underlying type `__m256i`, which is
75// interpreted as a vector of _signed_ `int32`s, which breaks some arithmetic
76// operations used in `GenericPacketMath.h`.
77template <>
78struct is_arithmetic<Packet4ul> : std::false_type {};
79#endif
80
81// Use the packet_traits defined in AVX512/PacketMath.h instead if we're going
82// to leverage AVX512 instructions.
83#ifndef EIGEN_VECTORIZE_AVX512
84template <>
85struct packet_traits<float> : default_packet_traits {
86 typedef Packet8f type;
87 typedef Packet4f half;
88 enum {
89 Vectorizable = 1,
90 AlignedOnScalar = 1,
91 size = 8,
92
93 HasCmp = 1,
94 HasDiv = 1,
95 HasReciprocal = EIGEN_FAST_MATH,
96 HasSin = EIGEN_FAST_MATH,
97 HasCos = EIGEN_FAST_MATH,
98 HasTan = EIGEN_FAST_MATH,
99 HasACos = 1,
100 HasASin = 1,
101 HasATan = 1,
102 HasATanh = 1,
103 HasSinh = 1,
104 HasCosh = 1,
105 HasASinh = 1,
106 HasACosh = 1,
107 HasLog = 1,
108 HasLog10 = 1,
109 HasExp = 1,
110 HasLog1p = 1,
111 HasExpm1 = 1,
112 HasPow = 1,
113 HasNdtri = 1,
114 HasBessel = 1,
115 HasSqrt = 1,
116 HasRsqrt = 1,
117 HasCbrt = 1,
118 HasTanh = EIGEN_FAST_MATH,
119 HasErf = EIGEN_FAST_MATH,
120 HasErfc = EIGEN_FAST_MATH,
121 };
122};
123template <>
124struct packet_traits<double> : default_packet_traits {
125 typedef Packet4d type;
126 typedef Packet2d half;
127 enum {
128 Vectorizable = 1,
129 AlignedOnScalar = 1,
130 size = 4,
131
132 HasCmp = 1,
133 HasDiv = 1,
134#ifdef EIGEN_VECTORIZE_AVX2
135 HasSin = EIGEN_FAST_MATH,
136 HasCos = EIGEN_FAST_MATH,
137 HasTan = EIGEN_FAST_MATH,
138#endif
139 HasSinh = 1,
140 HasCosh = 1,
141 HasASinh = 1,
142 HasACosh = 1,
143 HasTanh = EIGEN_FAST_MATH,
144 HasErf = 1,
145 HasErfc = 1,
146 HasLog = 1,
147 HasLog10 = 1,
148 HasExp = 1,
149 HasLog1p = 1,
150 HasExpm1 = 1,
151 HasPow = 1,
152 HasSqrt = 1,
153 HasRsqrt = 1,
154 HasCbrt = 1,
155 HasATan = 1,
156 HasATanh = 1,
157 };
158};
159
160template <>
161struct packet_traits<Eigen::half> : default_packet_traits {
162 typedef Packet8h type;
163 // There is no half-size packet for Packet8h.
164 typedef Packet8h half;
165 enum {
166 Vectorizable = 1,
167 AlignedOnScalar = 1,
168 size = 8,
169
170 HasCmp = 1,
171 HasAdd = 1,
172 HasSub = 1,
173 HasMul = 1,
174 HasDiv = 1,
175 HasSin = EIGEN_FAST_MATH,
176 HasCos = EIGEN_FAST_MATH,
177 HasNegate = 1,
178 HasAbs = 1,
179 HasMin = 1,
180 HasMax = 1,
181 HasConj = 1,
182 HasSetLinear = 0,
183 HasLog = 1,
184 HasLog1p = 1,
185 HasExpm1 = 1,
186 HasExp = 1,
187 HasSqrt = 1,
188 HasRsqrt = 1,
189 HasTanh = EIGEN_FAST_MATH,
190 HasErf = EIGEN_FAST_MATH,
191 HasBessel = 1,
192 HasNdtri = 1
193 };
194};
195
196template <>
197struct packet_traits<bfloat16> : default_packet_traits {
198 typedef Packet8bf type;
199 // There is no half-size packet for current Packet8bf.
200 // TODO: support as SSE path.
201 typedef Packet8bf half;
202 enum {
203 Vectorizable = 1,
204 AlignedOnScalar = 1,
205 size = 8,
206
207 HasCmp = 1,
208 HasAdd = 1,
209 HasSub = 1,
210 HasMul = 1,
211 HasDiv = 1,
212 HasSin = EIGEN_FAST_MATH,
213 HasCos = EIGEN_FAST_MATH,
214 HasNegate = 1,
215 HasAbs = 1,
216 HasMin = 1,
217 HasMax = 1,
218 HasConj = 1,
219 HasSetLinear = 0,
220 HasLog = 1,
221 HasLog1p = 1,
222 HasExpm1 = 1,
223 HasExp = 1,
224 HasSqrt = 1,
225 HasRsqrt = 1,
226 HasTanh = EIGEN_FAST_MATH,
227 HasErf = EIGEN_FAST_MATH,
228 HasBessel = 1,
229 HasNdtri = 1
230 };
231};
232
233template <>
234struct packet_traits<int> : default_packet_traits {
235 typedef Packet8i type;
236 typedef Packet4i half;
237 enum { Vectorizable = 1, AlignedOnScalar = 1, HasCmp = 1, HasDiv = 1, size = 8 };
238};
239template <>
240struct packet_traits<uint32_t> : default_packet_traits {
241 typedef Packet8ui type;
242 typedef Packet4ui half;
243 enum {
244 Vectorizable = 1,
245 AlignedOnScalar = 1,
246 size = 8,
247
248 HasDiv = 0,
249 HasNegate = 0,
250
251 HasCmp = 1,
252 HasMin = 1,
253 HasMax = 1,
254 HasShift = 1
255 };
256};
257
258#ifdef EIGEN_VECTORIZE_AVX2
259template <>
260struct packet_traits<int64_t> : default_packet_traits {
261 typedef Packet4l type;
262 typedef Packet2l half;
263 enum { Vectorizable = 1, AlignedOnScalar = 1, HasCmp = 1, size = 4 };
264};
265template <>
266struct packet_traits<uint64_t> : default_packet_traits {
267 typedef Packet4ul type;
268 // There is no half-size packet for current Packet4ul.
269 // TODO: support as SSE path.
270 typedef Packet4ul half;
271 enum {
272 Vectorizable = 1,
273 AlignedOnScalar = 1,
274 size = 4,
275
276 HasDiv = 0,
277 HasTranspose = 0,
278 HasNegate = 0,
279 HasCmp = 1,
280 HasShift = 1
281 };
282};
283#endif
284
285#endif
286
287template <>
288struct scalar_div_cost<float, true> : std::integral_constant<int, 14> {};
289template <>
290struct scalar_div_cost<double, true> : std::integral_constant<int, 16> {};
291
292template <>
293struct unpacket_traits<Packet8f> {
294 typedef float type;
295 typedef Packet4f half;
296 typedef Packet8i integer_packet;
297 typedef uint8_t mask_t;
298 enum {
299 size = 8,
300 alignment = Aligned32,
301 vectorizable = true,
302 masked_load_available = true,
303 masked_store_available = true
304#ifdef EIGEN_VECTORIZE_AVX512
305 ,
306 masked_fpops_available = true
307#endif
308 };
309};
310template <>
311struct unpacket_traits<Packet4d> {
312 typedef double type;
313 typedef Packet2d half;
314#ifdef EIGEN_VECTORIZE_AVX2
315 typedef Packet4l integer_packet;
316#endif
317 enum {
318 size = 4,
319 alignment = Aligned32,
320 vectorizable = true,
321 masked_load_available = false,
322 masked_store_available = false
323 };
324};
325template <>
326struct unpacket_traits<Packet8i> {
327 typedef int type;
328 typedef Packet4i half;
329 enum {
330 size = 8,
331 alignment = Aligned32,
332 vectorizable = true,
333 masked_load_available = false,
334 masked_store_available = false
335 };
336};
337template <>
338struct unpacket_traits<Packet8ui> {
339 typedef uint32_t type;
340 typedef Packet4ui half;
341 enum {
342 size = 8,
343 alignment = Aligned32,
344 vectorizable = true,
345 masked_load_available = false,
346 masked_store_available = false
347 };
348};
349#ifdef EIGEN_VECTORIZE_AVX2
350template <>
351struct unpacket_traits<Packet4l> {
352 typedef int64_t type;
353 typedef Packet2l half;
354 enum {
355 size = 4,
356 alignment = Aligned32,
357 vectorizable = true,
358 masked_load_available = false,
359 masked_store_available = false
360 };
361};
362template <>
363struct unpacket_traits<Packet4ul> {
364 typedef uint64_t type;
365 typedef Packet4ul half;
366 enum {
367 size = 4,
368 alignment = Aligned32,
369 vectorizable = true,
370 masked_load_available = false,
371 masked_store_available = false
372 };
373};
374#endif
375template <>
376struct unpacket_traits<Packet8bf> {
377 typedef bfloat16 type;
378 typedef Packet8bf half;
379 enum {
380 size = 8,
381 alignment = Aligned16,
382 vectorizable = true,
383 masked_load_available = false,
384 masked_store_available = false
385 };
386};
387
388// Helper function for bit packing snippet of low precision comparison.
389// It packs the flags from 16x16 to 8x16.
390EIGEN_STRONG_INLINE __m128i Pack16To8(const Packet8f& rf) {
391 return _mm_packs_epi32(_mm256_extractf128_si256(_mm256_castps_si256(rf), 0),
392 _mm256_extractf128_si256(_mm256_castps_si256(rf), 1));
393}
394
395#ifdef EIGEN_VECTORIZE_AVX2
396template <>
397EIGEN_STRONG_INLINE Packet4l pset1<Packet4l>(const int64_t& from) {
398 return _mm256_set1_epi64x(from);
399}
400template <>
401EIGEN_STRONG_INLINE Packet4ul pset1<Packet4ul>(const uint64_t& from) {
402 return _mm256_set1_epi64x(numext::bit_cast<uint64_t>(from));
403}
404template <>
405EIGEN_STRONG_INLINE Packet4l pzero(const Packet4l& /*a*/) {
406 return _mm256_setzero_si256();
407}
408template <>
409EIGEN_STRONG_INLINE Packet4ul pzero(const Packet4ul& /*a*/) {
410 return _mm256_setzero_si256();
411}
412template <>
413EIGEN_STRONG_INLINE Packet4l peven_mask(const Packet4l& /*a*/) {
414 return _mm256_set_epi64x(0ll, -1ll, 0ll, -1ll);
415}
416template <>
417EIGEN_STRONG_INLINE Packet4ul peven_mask(const Packet4ul& /*a*/) {
418 return _mm256_set_epi64x(0ll, -1ll, 0ll, -1ll);
419}
420template <>
421EIGEN_STRONG_INLINE Packet4l pload1<Packet4l>(const int64_t* from) {
422 return _mm256_set1_epi64x(*from);
423}
424template <>
425EIGEN_STRONG_INLINE Packet4ul pload1<Packet4ul>(const uint64_t* from) {
426 return _mm256_set1_epi64x(*from);
427}
428template <>
429EIGEN_STRONG_INLINE Packet4l padd<Packet4l>(const Packet4l& a, const Packet4l& b) {
430 return _mm256_add_epi64(a, b);
431}
432template <>
433EIGEN_STRONG_INLINE Packet4ul padd<Packet4ul>(const Packet4ul& a, const Packet4ul& b) {
434 return _mm256_add_epi64(a, b);
435}
436template <>
437EIGEN_STRONG_INLINE Packet4l plset<Packet4l>(const int64_t& a) {
438 return padd(pset1<Packet4l>(a), Packet4l(_mm256_set_epi64x(3ll, 2ll, 1ll, 0ll)));
439}
440template <>
441EIGEN_STRONG_INLINE Packet4ul plset<Packet4ul>(const uint64_t& a) {
442 return padd(pset1<Packet4ul>(a), Packet4ul(_mm256_set_epi64x(3ll, 2ll, 1ll, 0ll)));
443}
444template <>
445EIGEN_STRONG_INLINE Packet4l psub<Packet4l>(const Packet4l& a, const Packet4l& b) {
446 return _mm256_sub_epi64(a, b);
447}
448template <>
449EIGEN_STRONG_INLINE Packet4ul psub<Packet4ul>(const Packet4ul& a, const Packet4ul& b) {
450 return _mm256_sub_epi64(a, b);
451}
452template <>
453EIGEN_STRONG_INLINE Packet4l pnegate(const Packet4l& a) {
454 return psub(pzero(a), a);
455}
456template <>
457EIGEN_STRONG_INLINE Packet4l pcmp_le(const Packet4l& a, const Packet4l& b) {
458 return _mm256_xor_si256(_mm256_cmpgt_epi64(a, b), _mm256_set1_epi32(-1));
459}
460template <>
461EIGEN_STRONG_INLINE Packet4ul pcmp_le(const Packet4ul& a, const Packet4ul& b) {
462 return (Packet4ul)pcmp_le((Packet4l)psub(a, pset1<Packet4ul>(0x8000000000000000UL)),
463 (Packet4l)psub(b, pset1<Packet4ul>(0x8000000000000000UL)));
464}
465template <>
466EIGEN_STRONG_INLINE Packet4l pcmp_lt(const Packet4l& a, const Packet4l& b) {
467 return _mm256_cmpgt_epi64(b, a);
468}
469template <>
470EIGEN_STRONG_INLINE Packet4ul pcmp_lt(const Packet4ul& a, const Packet4ul& b) {
471 return (Packet4ul)pcmp_lt((Packet4l)psub(a, pset1<Packet4ul>(0x8000000000000000UL)),
472 (Packet4l)psub(b, pset1<Packet4ul>(0x8000000000000000UL)));
473}
474template <>
475EIGEN_STRONG_INLINE Packet4l pcmp_eq(const Packet4l& a, const Packet4l& b) {
476 return _mm256_cmpeq_epi64(a, b);
477}
478template <>
479EIGEN_STRONG_INLINE Packet4ul pcmp_eq(const Packet4ul& a, const Packet4ul& b) {
480 return _mm256_cmpeq_epi64(a, b);
481}
482template <>
483EIGEN_STRONG_INLINE Packet4l ptrue<Packet4l>(const Packet4l& a) {
484 return _mm256_cmpeq_epi64(a, a);
485}
486template <>
487EIGEN_STRONG_INLINE Packet4ul ptrue<Packet4ul>(const Packet4ul& a) {
488 return _mm256_cmpeq_epi64(a, a);
489}
490template <>
491EIGEN_STRONG_INLINE Packet4l pand<Packet4l>(const Packet4l& a, const Packet4l& b) {
492 return _mm256_and_si256(a, b);
493}
494template <>
495EIGEN_STRONG_INLINE Packet4l por<Packet4l>(const Packet4l& a, const Packet4l& b) {
496 return _mm256_or_si256(a, b);
497}
498template <>
499EIGEN_STRONG_INLINE Packet4l pxor<Packet4l>(const Packet4l& a, const Packet4l& b) {
500 return _mm256_xor_si256(a, b);
501}
502template <>
503EIGEN_STRONG_INLINE Packet4ul pxor<Packet4ul>(const Packet4ul& a, const Packet4ul& b) {
504 return _mm256_xor_si256(a, b);
505}
506template <>
507EIGEN_STRONG_INLINE Packet4l pandnot<Packet4l>(const Packet4l& a, const Packet4l& b) {
508 return _mm256_andnot_si256(b, a);
509}
510template <int N>
511EIGEN_STRONG_INLINE Packet4l plogical_shift_right(const Packet4l& a) {
512 return _mm256_srli_epi64(a, N);
513}
514template <int N>
515EIGEN_STRONG_INLINE Packet4l plogical_shift_left(const Packet4l& a) {
516 return _mm256_slli_epi64(a, N);
517}
518#ifdef EIGEN_VECTORIZE_AVX512FP16
519template <int N>
520EIGEN_STRONG_INLINE Packet4l parithmetic_shift_right(const Packet4l& a) {
521 return _mm256_srai_epi64(a, N);
522}
523#else
524template <int N>
525EIGEN_STRONG_INLINE std::enable_if_t<(N == 0), Packet4l> parithmetic_shift_right(const Packet4l& a) {
526 return a;
527}
528template <int N>
529EIGEN_STRONG_INLINE std::enable_if_t<(N > 0) && (N < 32), Packet4l> parithmetic_shift_right(const Packet4l& a) {
530 __m256i hi_word = _mm256_srai_epi32(a, N);
531 __m256i lo_word = _mm256_srli_epi64(a, N);
532 return _mm256_blend_epi32(hi_word, lo_word, 0b01010101);
533}
534template <int N>
535EIGEN_STRONG_INLINE std::enable_if_t<(N >= 32) && (N < 63), Packet4l> parithmetic_shift_right(const Packet4l& a) {
536 __m256i hi_word = _mm256_srai_epi32(a, 31);
537 __m256i lo_word = _mm256_shuffle_epi32(_mm256_srai_epi32(a, N - 32), (shuffle_mask<1, 1, 3, 3>::mask));
538 return _mm256_blend_epi32(hi_word, lo_word, 0b01010101);
539}
540template <int N>
541EIGEN_STRONG_INLINE std::enable_if_t<(N == 63), Packet4l> parithmetic_shift_right(const Packet4l& a) {
542 return _mm256_cmpgt_epi64(_mm256_setzero_si256(), a);
543}
544template <int N>
545EIGEN_STRONG_INLINE std::enable_if_t<(N < 0) || (N > 63), Packet4l> parithmetic_shift_right(const Packet4l& a) {
546 return parithmetic_shift_right<int(N & 63)>(a);
547}
548#endif
549template <int N>
550EIGEN_STRONG_INLINE Packet4ul parithmetic_shift_right(const Packet4ul& a) {
551 return _mm256_srli_epi64(a, N);
552}
553template <int N>
554EIGEN_STRONG_INLINE Packet4ul plogical_shift_right(const Packet4ul& a) {
555 return _mm256_srli_epi64(a, N);
556}
557template <int N>
558EIGEN_STRONG_INLINE Packet4ul plogical_shift_left(const Packet4ul& a) {
559 return _mm256_slli_epi64(a, N);
560}
561template <>
562EIGEN_STRONG_INLINE Packet4l pload<Packet4l>(const int64_t* from) {
563 EIGEN_DEBUG_ALIGNED_LOAD return _mm256_load_si256(reinterpret_cast<const __m256i*>(from));
564}
565template <>
566EIGEN_STRONG_INLINE Packet4ul pload<Packet4ul>(const uint64_t* from) {
567 EIGEN_DEBUG_ALIGNED_LOAD return _mm256_load_si256(reinterpret_cast<const __m256i*>(from));
568}
569template <>
570EIGEN_STRONG_INLINE Packet4l ploadu<Packet4l>(const int64_t* from) {
571 EIGEN_DEBUG_UNALIGNED_LOAD return _mm256_loadu_si256(reinterpret_cast<const __m256i*>(from));
572}
573template <>
574EIGEN_STRONG_INLINE Packet4ul ploadu<Packet4ul>(const uint64_t* from) {
575 EIGEN_DEBUG_UNALIGNED_LOAD return _mm256_loadu_si256(reinterpret_cast<const __m256i*>(from));
576}
577// Loads 2 int64_ts from memory a returns the packet {a0, a0, a1, a1}
578template <>
579EIGEN_STRONG_INLINE Packet4l ploaddup<Packet4l>(const int64_t* from) {
580 const Packet4l a = _mm256_castsi128_si256(_mm_loadu_si128(reinterpret_cast<const __m128i*>(from)));
581 return _mm256_permutevar8x32_epi32(a, _mm256_setr_epi32(0, 1, 0, 1, 2, 3, 2, 3));
582}
583// Loads 2 uint64_ts from memory a returns the packet {a0, a0, a1, a1}
584template <>
585EIGEN_STRONG_INLINE Packet4ul ploaddup<Packet4ul>(const uint64_t* from) {
586 const Packet4ul a = _mm256_castsi128_si256(_mm_loadu_si128(reinterpret_cast<const __m128i*>(from)));
587 return _mm256_permutevar8x32_epi32(a, _mm256_setr_epi32(0, 1, 0, 1, 2, 3, 2, 3));
588}
589template <>
590EIGEN_STRONG_INLINE void pstore<int64_t>(int64_t* to, const Packet4l& from) {
591 EIGEN_DEBUG_ALIGNED_STORE _mm256_store_si256(reinterpret_cast<__m256i*>(to), from);
592}
593template <>
594EIGEN_STRONG_INLINE void pstore<uint64_t>(uint64_t* to, const Packet4ul& from) {
595 EIGEN_DEBUG_ALIGNED_STORE _mm256_store_si256(reinterpret_cast<__m256i*>(to), from);
596}
597template <>
598EIGEN_STRONG_INLINE void pstoreu<int64_t>(int64_t* to, const Packet4l& from) {
599 EIGEN_DEBUG_UNALIGNED_STORE _mm256_storeu_si256(reinterpret_cast<__m256i*>(to), from);
600}
601template <>
602EIGEN_STRONG_INLINE void pstoreu<uint64_t>(uint64_t* to, const Packet4ul& from) {
603 EIGEN_DEBUG_UNALIGNED_STORE _mm256_storeu_si256(reinterpret_cast<__m256i*>(to), from);
604}
605template <>
606EIGEN_DEVICE_FUNC inline Packet4l pgather<int64_t, Packet4l>(const int64_t* from, Index stride) {
607 return _mm256_set_epi64x(from[3 * stride], from[2 * stride], from[1 * stride], from[0 * stride]);
608}
609template <>
610EIGEN_DEVICE_FUNC inline Packet4ul pgather<uint64_t, Packet4ul>(const uint64_t* from, Index stride) {
611 return _mm256_set_epi64x(from[3 * stride], from[2 * stride], from[1 * stride], from[0 * stride]);
612}
613template <>
614EIGEN_DEVICE_FUNC inline void pscatter<int64_t, Packet4l>(int64_t* to, const Packet4l& from, Index stride) {
615 __m128i low = _mm256_extractf128_si256(from, 0);
616 to[stride * 0] = _mm_extract_epi64_0(low);
617 to[stride * 1] = _mm_extract_epi64_1(low);
618
619 __m128i high = _mm256_extractf128_si256(from, 1);
620 to[stride * 2] = _mm_extract_epi64_0(high);
621 to[stride * 3] = _mm_extract_epi64_1(high);
622}
623template <>
624EIGEN_DEVICE_FUNC inline void pscatter<uint64_t, Packet4ul>(uint64_t* to, const Packet4ul& from, Index stride) {
625 __m128i low = _mm256_extractf128_si256(from, 0);
626 to[stride * 0] = _mm_extract_epi64_0(low);
627 to[stride * 1] = _mm_extract_epi64_1(low);
628
629 __m128i high = _mm256_extractf128_si256(from, 1);
630 to[stride * 2] = _mm_extract_epi64_0(high);
631 to[stride * 3] = _mm_extract_epi64_1(high);
632}
633template <>
634EIGEN_STRONG_INLINE void pstore1<Packet4l>(int64_t* to, const int64_t& a) {
635 Packet4l pa = pset1<Packet4l>(a);
636 pstore(to, pa);
637}
638template <>
639EIGEN_STRONG_INLINE void pstore1<Packet4ul>(uint64_t* to, const uint64_t& a) {
640 Packet4ul pa = pset1<Packet4ul>(a);
641 pstore(to, pa);
642}
643template <>
644EIGEN_STRONG_INLINE int64_t pfirst<Packet4l>(const Packet4l& a) {
645 return _mm_extract_epi64_0(_mm256_castsi256_si128(a));
646}
647template <>
648EIGEN_STRONG_INLINE uint64_t pfirst<Packet4ul>(const Packet4ul& a) {
649 return _mm_extract_epi64_0(_mm256_castsi256_si128(a));
650}
651
652#define MM256_SHUFFLE_EPI64(A, B, M) _mm256_shuffle_pd(_mm256_castsi256_pd(A), _mm256_castsi256_pd(B), M)
653EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet4l, 4>& kernel) {
654 __m256d T0 = MM256_SHUFFLE_EPI64(kernel.packet[0], kernel.packet[1], 15);
655 __m256d T1 = MM256_SHUFFLE_EPI64(kernel.packet[0], kernel.packet[1], 0);
656 __m256d T2 = MM256_SHUFFLE_EPI64(kernel.packet[2], kernel.packet[3], 15);
657 __m256d T3 = MM256_SHUFFLE_EPI64(kernel.packet[2], kernel.packet[3], 0);
658
659 kernel.packet[1] = _mm256_castpd_si256(_mm256_permute2f128_pd(T0, T2, 32));
660 kernel.packet[3] = _mm256_castpd_si256(_mm256_permute2f128_pd(T0, T2, 49));
661 kernel.packet[0] = _mm256_castpd_si256(_mm256_permute2f128_pd(T1, T3, 32));
662 kernel.packet[2] = _mm256_castpd_si256(_mm256_permute2f128_pd(T1, T3, 49));
663}
664EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet4ul, 4>& kernel) {
665 ptranspose((PacketBlock<Packet4l, 4>&)kernel);
666}
667template <>
668EIGEN_STRONG_INLINE Packet4l pmin<Packet4l>(const Packet4l& a, const Packet4l& b) {
669 __m256i cmp = _mm256_cmpgt_epi64(a, b);
670 __m256i a_min = _mm256_andnot_si256(cmp, a);
671 __m256i b_min = _mm256_and_si256(cmp, b);
672 return Packet4l(_mm256_or_si256(a_min, b_min));
673}
674template <>
675EIGEN_STRONG_INLINE Packet4ul pmin<Packet4ul>(const Packet4ul& a, const Packet4ul& b) {
676 return padd((Packet4ul)pmin((Packet4l)psub(a, pset1<Packet4ul>(0x8000000000000000UL)),
677 (Packet4l)psub(b, pset1<Packet4ul>(0x8000000000000000UL))),
678 pset1<Packet4ul>(0x8000000000000000UL));
679}
680template <>
681EIGEN_STRONG_INLINE Packet4l pmax<Packet4l>(const Packet4l& a, const Packet4l& b) {
682 __m256i cmp = _mm256_cmpgt_epi64(a, b);
683 __m256i a_min = _mm256_and_si256(cmp, a);
684 __m256i b_min = _mm256_andnot_si256(cmp, b);
685 return Packet4l(_mm256_or_si256(a_min, b_min));
686}
687template <>
688EIGEN_STRONG_INLINE Packet4ul pmax<Packet4ul>(const Packet4ul& a, const Packet4ul& b) {
689 return padd((Packet4ul)pmax((Packet4l)psub(a, pset1<Packet4ul>(0x8000000000000000UL)),
690 (Packet4l)psub(b, pset1<Packet4ul>(0x8000000000000000UL))),
691 pset1<Packet4ul>(0x8000000000000000UL));
692}
693template <>
694EIGEN_STRONG_INLINE Packet4l pabs<Packet4l>(const Packet4l& a) {
695 Packet4l pz = pzero<Packet4l>(a);
696 Packet4l cmp = _mm256_cmpgt_epi64(a, pz);
697 return psub(cmp, pxor(a, cmp));
698}
699template <>
700EIGEN_STRONG_INLINE Packet4l pmul<Packet4l>(const Packet4l& a, const Packet4l& b) {
701 // 64-bit mul requires avx512, so do this with 32-bit multiplication
702 __m256i upper32_a = _mm256_srli_epi64(a, 32);
703 __m256i upper32_b = _mm256_srli_epi64(b, 32);
704
705 // upper * lower
706 __m256i mul1 = _mm256_mul_epu32(upper32_a, b);
707 __m256i mul2 = _mm256_mul_epu32(upper32_b, a);
708 // Gives us both upper*upper and lower*lower
709 __m256i mul3 = _mm256_mul_epu32(a, b);
710
711 __m256i high = _mm256_slli_epi64(_mm256_add_epi64(mul1, mul2), 32);
712 return _mm256_add_epi64(high, mul3);
713}
714template <>
715EIGEN_STRONG_INLINE Packet4ul pmul<Packet4ul>(const Packet4ul& a, const Packet4ul& b) {
716 return (Packet4ul)pmul<Packet4l>((Packet4l)a, (Packet4l)b);
717}
718#endif
719
720template <>
721EIGEN_STRONG_INLINE Packet8f pset1<Packet8f>(const float& from) {
722 return _mm256_set1_ps(from);
723}
724template <>
725EIGEN_STRONG_INLINE Packet4d pset1<Packet4d>(const double& from) {
726 return _mm256_set1_pd(from);
727}
728template <>
729EIGEN_STRONG_INLINE Packet8i pset1<Packet8i>(const int& from) {
730 return _mm256_set1_epi32(from);
731}
732template <>
733EIGEN_STRONG_INLINE Packet8ui pset1<Packet8ui>(const uint32_t& from) {
734 return _mm256_set1_epi32(from);
735}
736
737template <>
738EIGEN_STRONG_INLINE Packet8f pset1frombits<Packet8f>(unsigned int from) {
739 return _mm256_castsi256_ps(pset1<Packet8i>(from));
740}
741template <>
742EIGEN_STRONG_INLINE Packet4d pset1frombits<Packet4d>(uint64_t from) {
743 return _mm256_castsi256_pd(_mm256_set1_epi64x(from));
744}
745
746template <>
747EIGEN_STRONG_INLINE Packet8f pzero(const Packet8f& /*a*/) {
748 return _mm256_setzero_ps();
749}
750template <>
751EIGEN_STRONG_INLINE Packet4d pzero(const Packet4d& /*a*/) {
752 return _mm256_setzero_pd();
753}
754template <>
755EIGEN_STRONG_INLINE Packet8i pzero(const Packet8i& /*a*/) {
756 return _mm256_setzero_si256();
757}
758template <>
759EIGEN_STRONG_INLINE Packet8ui pzero(const Packet8ui& /*a*/) {
760 return _mm256_setzero_si256();
761}
762
763template <>
764EIGEN_STRONG_INLINE Packet8f peven_mask(const Packet8f& /*a*/) {
765 Packet8f r = _mm256_castsi256_ps(_mm256_set_epi32(0, -1, 0, -1, 0, -1, 0, -1));
766 EIGEN_FAST_MATH_CONSTANT_BARRIER(r);
767 return r;
768}
769template <>
770EIGEN_STRONG_INLINE Packet8i peven_mask(const Packet8i& /*a*/) {
771 return _mm256_set_epi32(0, -1, 0, -1, 0, -1, 0, -1);
772}
773template <>
774EIGEN_STRONG_INLINE Packet8ui peven_mask(const Packet8ui& /*a*/) {
775 return _mm256_set_epi32(0, -1, 0, -1, 0, -1, 0, -1);
776}
777template <>
778EIGEN_STRONG_INLINE Packet4d peven_mask(const Packet4d& /*a*/) {
779 Packet4d r = _mm256_castsi256_pd(_mm256_set_epi32(0, 0, -1, -1, 0, 0, -1, -1));
780 EIGEN_FAST_MATH_CONSTANT_BARRIER(r);
781 return r;
782}
783
784template <>
785EIGEN_STRONG_INLINE Packet8f pload1<Packet8f>(const float* from) {
786 return _mm256_broadcast_ss(from);
787}
788template <>
789EIGEN_STRONG_INLINE Packet4d pload1<Packet4d>(const double* from) {
790 return _mm256_broadcast_sd(from);
791}
792
793template <>
794EIGEN_STRONG_INLINE Packet8f padd<Packet8f>(const Packet8f& a, const Packet8f& b) {
795 return _mm256_add_ps(a, b);
796}
797#ifdef EIGEN_VECTORIZE_AVX512
798template <>
799EIGEN_STRONG_INLINE Packet8f padd<Packet8f>(const Packet8f& a, const Packet8f& b, uint8_t umask) {
800 __mmask16 mask = static_cast<__mmask16>(umask & 0x00FF);
801 return _mm512_castps512_ps256(_mm512_maskz_add_ps(mask, _mm512_castps256_ps512(a), _mm512_castps256_ps512(b)));
802}
803#endif
804template <>
805EIGEN_STRONG_INLINE Packet4d padd<Packet4d>(const Packet4d& a, const Packet4d& b) {
806 return _mm256_add_pd(a, b);
807}
808template <>
809EIGEN_STRONG_INLINE Packet8i padd<Packet8i>(const Packet8i& a, const Packet8i& b) {
810#ifdef EIGEN_VECTORIZE_AVX2
811 return _mm256_add_epi32(a, b);
812#else
813 __m128i lo = _mm_add_epi32(_mm256_extractf128_si256(a, 0), _mm256_extractf128_si256(b, 0));
814 __m128i hi = _mm_add_epi32(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1));
815 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
816#endif
817}
818template <>
819EIGEN_STRONG_INLINE Packet8ui padd<Packet8ui>(const Packet8ui& a, const Packet8ui& b) {
820#ifdef EIGEN_VECTORIZE_AVX2
821 return _mm256_add_epi32(a, b);
822#else
823 __m128i lo = _mm_add_epi32(_mm256_extractf128_si256(a, 0), _mm256_extractf128_si256(b, 0));
824 __m128i hi = _mm_add_epi32(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1));
825 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
826#endif
827}
828
829template <>
830EIGEN_STRONG_INLINE Packet8f plset<Packet8f>(const float& a) {
831 return padd(pset1<Packet8f>(a), _mm256_set_ps(7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0));
832}
833template <>
834EIGEN_STRONG_INLINE Packet4d plset<Packet4d>(const double& a) {
835 return padd(pset1<Packet4d>(a), _mm256_set_pd(3.0, 2.0, 1.0, 0.0));
836}
837template <>
838EIGEN_STRONG_INLINE Packet8i plset<Packet8i>(const int& a) {
839 return padd(pset1<Packet8i>(a), (Packet8i)_mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0));
840}
841template <>
842EIGEN_STRONG_INLINE Packet8ui plset<Packet8ui>(const uint32_t& a) {
843 return padd(pset1<Packet8ui>(a), (Packet8ui)_mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0));
844}
845
846template <>
847EIGEN_STRONG_INLINE Packet8f psub<Packet8f>(const Packet8f& a, const Packet8f& b) {
848 return _mm256_sub_ps(a, b);
849}
850template <>
851EIGEN_STRONG_INLINE Packet4d psub<Packet4d>(const Packet4d& a, const Packet4d& b) {
852 return _mm256_sub_pd(a, b);
853}
854template <>
855EIGEN_STRONG_INLINE Packet8i psub<Packet8i>(const Packet8i& a, const Packet8i& b) {
856#ifdef EIGEN_VECTORIZE_AVX2
857 return _mm256_sub_epi32(a, b);
858#else
859 __m128i lo = _mm_sub_epi32(_mm256_extractf128_si256(a, 0), _mm256_extractf128_si256(b, 0));
860 __m128i hi = _mm_sub_epi32(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1));
861 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
862#endif
863}
864template <>
865EIGEN_STRONG_INLINE Packet8ui psub<Packet8ui>(const Packet8ui& a, const Packet8ui& b) {
866#ifdef EIGEN_VECTORIZE_AVX2
867 return _mm256_sub_epi32(a, b);
868#else
869 __m128i lo = _mm_sub_epi32(_mm256_extractf128_si256(a, 0), _mm256_extractf128_si256(b, 0));
870 __m128i hi = _mm_sub_epi32(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1));
871 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
872#endif
873}
874
875template <>
876EIGEN_STRONG_INLINE Packet8f pnegate(const Packet8f& a) {
877 const Packet8f mask = _mm256_castsi256_ps(_mm256_set1_epi32(SIGN_MASK_I32));
878 return _mm256_xor_ps(a, mask);
879}
880template <>
881EIGEN_STRONG_INLINE Packet4d pnegate(const Packet4d& a) {
882 const Packet4d mask = _mm256_castsi256_pd(_mm256_set1_epi64x(SIGN_MASK_I64));
883 return _mm256_xor_pd(a, mask);
884}
885template <>
886EIGEN_STRONG_INLINE Packet8i pnegate(const Packet8i& a) {
887 return psub(pzero(a), a);
888}
889
890template <>
891EIGEN_STRONG_INLINE Packet8f pmul<Packet8f>(const Packet8f& a, const Packet8f& b) {
892 return _mm256_mul_ps(a, b);
893}
894template <>
895EIGEN_STRONG_INLINE Packet4d pmul<Packet4d>(const Packet4d& a, const Packet4d& b) {
896 return _mm256_mul_pd(a, b);
897}
898template <>
899EIGEN_STRONG_INLINE Packet8i pmul<Packet8i>(const Packet8i& a, const Packet8i& b) {
900#ifdef EIGEN_VECTORIZE_AVX2
901 return _mm256_mullo_epi32(a, b);
902#else
903 const __m128i lo = _mm_mullo_epi32(_mm256_extractf128_si256(a, 0), _mm256_extractf128_si256(b, 0));
904 const __m128i hi = _mm_mullo_epi32(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1));
905 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
906#endif
907}
908template <>
909EIGEN_STRONG_INLINE Packet8ui pmul<Packet8ui>(const Packet8ui& a, const Packet8ui& b) {
910#ifdef EIGEN_VECTORIZE_AVX2
911 return _mm256_mullo_epi32(a, b);
912#else
913 const __m128i lo = _mm_mullo_epi32(_mm256_extractf128_si256(a, 0), _mm256_extractf128_si256(b, 0));
914 const __m128i hi = _mm_mullo_epi32(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1));
915 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
916#endif
917}
918
919template <>
920EIGEN_STRONG_INLINE Packet8f pdiv<Packet8f>(const Packet8f& a, const Packet8f& b) {
921 return _mm256_div_ps(a, b);
922}
923template <>
924EIGEN_STRONG_INLINE Packet4d pdiv<Packet4d>(const Packet4d& a, const Packet4d& b) {
925 return _mm256_div_pd(a, b);
926}
927
928template <>
929EIGEN_STRONG_INLINE Packet8i pdiv<Packet8i>(const Packet8i& a, const Packet8i& b) {
930#ifdef EIGEN_VECTORIZE_AVX512
931 return _mm512_cvttpd_epi32(_mm512_div_pd(_mm512_cvtepi32_pd(a), _mm512_cvtepi32_pd(b)));
932#else
933 Packet4i lo = pdiv<Packet4i>(_mm256_extractf128_si256(a, 0), _mm256_extractf128_si256(b, 0));
934 Packet4i hi = pdiv<Packet4i>(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1));
935 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), hi, 1);
936#endif
937}
938
939#ifdef EIGEN_VECTORIZE_FMA
940template <>
941EIGEN_STRONG_INLINE Packet8f pmadd(const Packet8f& a, const Packet8f& b, const Packet8f& c) {
942 return _mm256_fmadd_ps(a, b, c);
943}
944template <>
945EIGEN_STRONG_INLINE Packet4d pmadd(const Packet4d& a, const Packet4d& b, const Packet4d& c) {
946 return _mm256_fmadd_pd(a, b, c);
947}
948
949template <>
950EIGEN_STRONG_INLINE Packet8f pmsub(const Packet8f& a, const Packet8f& b, const Packet8f& c) {
951 return _mm256_fmsub_ps(a, b, c);
952}
953
954template <>
955EIGEN_STRONG_INLINE Packet4d pmsub(const Packet4d& a, const Packet4d& b, const Packet4d& c) {
956 return _mm256_fmsub_pd(a, b, c);
957}
958
959template <>
960EIGEN_STRONG_INLINE Packet8f pnmadd(const Packet8f& a, const Packet8f& b, const Packet8f& c) {
961 return _mm256_fnmadd_ps(a, b, c);
962}
963
964template <>
965EIGEN_STRONG_INLINE Packet4d pnmadd(const Packet4d& a, const Packet4d& b, const Packet4d& c) {
966 return _mm256_fnmadd_pd(a, b, c);
967}
968
969template <>
970EIGEN_STRONG_INLINE Packet8f pnmsub(const Packet8f& a, const Packet8f& b, const Packet8f& c) {
971 return _mm256_fnmsub_ps(a, b, c);
972}
973
974template <>
975EIGEN_STRONG_INLINE Packet4d pnmsub(const Packet4d& a, const Packet4d& b, const Packet4d& c) {
976 return _mm256_fnmsub_pd(a, b, c);
977}
978
979#endif
980
981template <>
982EIGEN_STRONG_INLINE Packet8f pcmp_le(const Packet8f& a, const Packet8f& b) {
983 return _mm256_cmp_ps(a, b, _CMP_LE_OQ);
984}
985template <>
986EIGEN_STRONG_INLINE Packet8f pcmp_lt(const Packet8f& a, const Packet8f& b) {
987 return _mm256_cmp_ps(a, b, _CMP_LT_OQ);
988}
989template <>
990EIGEN_STRONG_INLINE Packet8f pcmp_lt_or_nan(const Packet8f& a, const Packet8f& b) {
991 return _mm256_cmp_ps(a, b, _CMP_NGE_UQ);
992}
993template <>
994EIGEN_STRONG_INLINE Packet8f pcmp_eq(const Packet8f& a, const Packet8f& b) {
995 return _mm256_cmp_ps(a, b, _CMP_EQ_OQ);
996}
997template <>
998EIGEN_STRONG_INLINE Packet8f pisnan(const Packet8f& a) {
999 return _mm256_cmp_ps(a, a, _CMP_UNORD_Q);
1000}
1001
1002template <>
1003EIGEN_STRONG_INLINE Packet4d pcmp_le(const Packet4d& a, const Packet4d& b) {
1004 return _mm256_cmp_pd(a, b, _CMP_LE_OQ);
1005}
1006template <>
1007EIGEN_STRONG_INLINE Packet4d pcmp_lt(const Packet4d& a, const Packet4d& b) {
1008 return _mm256_cmp_pd(a, b, _CMP_LT_OQ);
1009}
1010template <>
1011EIGEN_STRONG_INLINE Packet4d pcmp_lt_or_nan(const Packet4d& a, const Packet4d& b) {
1012 return _mm256_cmp_pd(a, b, _CMP_NGE_UQ);
1013}
1014template <>
1015EIGEN_STRONG_INLINE Packet4d pcmp_eq(const Packet4d& a, const Packet4d& b) {
1016 return _mm256_cmp_pd(a, b, _CMP_EQ_OQ);
1017}
1018
1019template <>
1020EIGEN_STRONG_INLINE Packet8i pcmp_le(const Packet8i& a, const Packet8i& b) {
1021#ifdef EIGEN_VECTORIZE_AVX2
1022 return _mm256_xor_si256(_mm256_cmpgt_epi32(a, b), _mm256_set1_epi32(-1));
1023#else
1024 __m128i lo = _mm_cmpgt_epi32(_mm256_extractf128_si256(a, 0), _mm256_extractf128_si256(b, 0));
1025 lo = _mm_xor_si128(lo, _mm_set1_epi32(-1));
1026 __m128i hi = _mm_cmpgt_epi32(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1));
1027 hi = _mm_xor_si128(hi, _mm_set1_epi32(-1));
1028 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
1029#endif
1030}
1031template <>
1032EIGEN_STRONG_INLINE Packet8i pcmp_lt(const Packet8i& a, const Packet8i& b) {
1033#ifdef EIGEN_VECTORIZE_AVX2
1034 return _mm256_cmpgt_epi32(b, a);
1035#else
1036 __m128i lo = _mm_cmpgt_epi32(_mm256_extractf128_si256(b, 0), _mm256_extractf128_si256(a, 0));
1037 __m128i hi = _mm_cmpgt_epi32(_mm256_extractf128_si256(b, 1), _mm256_extractf128_si256(a, 1));
1038 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
1039#endif
1040}
1041template <>
1042EIGEN_STRONG_INLINE Packet8i pcmp_eq(const Packet8i& a, const Packet8i& b) {
1043#ifdef EIGEN_VECTORIZE_AVX2
1044 return _mm256_cmpeq_epi32(a, b);
1045#else
1046 __m128i lo = _mm_cmpeq_epi32(_mm256_extractf128_si256(a, 0), _mm256_extractf128_si256(b, 0));
1047 __m128i hi = _mm_cmpeq_epi32(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1));
1048 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
1049#endif
1050}
1051template <>
1052EIGEN_STRONG_INLINE Packet8ui pcmp_eq(const Packet8ui& a, const Packet8ui& b) {
1053#ifdef EIGEN_VECTORIZE_AVX2
1054 return _mm256_cmpeq_epi32(a, b);
1055#else
1056 __m128i lo = _mm_cmpeq_epi32(_mm256_extractf128_si256(a, 0), _mm256_extractf128_si256(b, 0));
1057 __m128i hi = _mm_cmpeq_epi32(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1));
1058 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
1059#endif
1060}
1061
1062template <>
1063EIGEN_STRONG_INLINE Packet8f pmin<Packet8f>(const Packet8f& a, const Packet8f& b) {
1064#if EIGEN_GNUC_STRICT_LESS_THAN(6, 3, 0)
1065 // There appears to be a bug in GCC, by which the optimizer may flip
1066 // the argument order in calls to _mm_min_ps/_mm_max_ps, so we have to
1067 // resort to inline ASM here. This is supposed to be fixed in gcc6.3,
1068 // see also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72867
1069 Packet8f res;
1070 asm("vminps %[a], %[b], %[res]" : [res] "=x"(res) : [a] "x"(a), [b] "x"(b));
1071 return res;
1072#else
1073 // Arguments are swapped to match NaN propagation behavior of std::min.
1074 return _mm256_min_ps(b, a);
1075#endif
1076}
1077template <>
1078EIGEN_STRONG_INLINE Packet4d pmin<Packet4d>(const Packet4d& a, const Packet4d& b) {
1079#if EIGEN_GNUC_STRICT_LESS_THAN(6, 3, 0)
1080 // See pmin above
1081 Packet4d res;
1082 asm("vminpd %[a], %[b], %[res]" : [res] "=x"(res) : [a] "x"(a), [b] "x"(b));
1083 return res;
1084#else
1085 // Arguments are swapped to match NaN propagation behavior of std::min.
1086 return _mm256_min_pd(b, a);
1087#endif
1088}
1089template <>
1090EIGEN_STRONG_INLINE Packet8i pmin<Packet8i>(const Packet8i& a, const Packet8i& b) {
1091#ifdef EIGEN_VECTORIZE_AVX2
1092 return _mm256_min_epi32(a, b);
1093#else
1094 __m128i lo = _mm_min_epi32(_mm256_extractf128_si256(a, 0), _mm256_extractf128_si256(b, 0));
1095 __m128i hi = _mm_min_epi32(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1));
1096 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
1097#endif
1098}
1099template <>
1100EIGEN_STRONG_INLINE Packet8ui pmin<Packet8ui>(const Packet8ui& a, const Packet8ui& b) {
1101#ifdef EIGEN_VECTORIZE_AVX2
1102 return _mm256_min_epu32(a, b);
1103#else
1104 __m128i lo = _mm_min_epu32(_mm256_extractf128_si256(a, 0), _mm256_extractf128_si256(b, 0));
1105 __m128i hi = _mm_min_epu32(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1));
1106 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
1107#endif
1108}
1109
1110template <>
1111EIGEN_STRONG_INLINE Packet8f pmax<Packet8f>(const Packet8f& a, const Packet8f& b) {
1112#if EIGEN_GNUC_STRICT_LESS_THAN(6, 3, 0)
1113 // See pmin above
1114 Packet8f res;
1115 asm("vmaxps %[a], %[b], %[res]" : [res] "=x"(res) : [a] "x"(a), [b] "x"(b));
1116 return res;
1117#else
1118 // Arguments are swapped to match NaN propagation behavior of std::max.
1119 return _mm256_max_ps(b, a);
1120#endif
1121}
1122template <>
1123EIGEN_STRONG_INLINE Packet4d pmax<Packet4d>(const Packet4d& a, const Packet4d& b) {
1124#if EIGEN_GNUC_STRICT_LESS_THAN(6, 3, 0)
1125 // See pmin above
1126 Packet4d res;
1127 asm("vmaxpd %[a], %[b], %[res]" : [res] "=x"(res) : [a] "x"(a), [b] "x"(b));
1128 return res;
1129#else
1130 // Arguments are swapped to match NaN propagation behavior of std::max.
1131 return _mm256_max_pd(b, a);
1132#endif
1133}
1134template <>
1135EIGEN_STRONG_INLINE Packet8i pmax<Packet8i>(const Packet8i& a, const Packet8i& b) {
1136#ifdef EIGEN_VECTORIZE_AVX2
1137 return _mm256_max_epi32(a, b);
1138#else
1139 __m128i lo = _mm_max_epi32(_mm256_extractf128_si256(a, 0), _mm256_extractf128_si256(b, 0));
1140 __m128i hi = _mm_max_epi32(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1));
1141 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
1142#endif
1143}
1144template <>
1145EIGEN_STRONG_INLINE Packet8ui pmax<Packet8ui>(const Packet8ui& a, const Packet8ui& b) {
1146#ifdef EIGEN_VECTORIZE_AVX2
1147 return _mm256_max_epu32(a, b);
1148#else
1149 __m128i lo = _mm_max_epu32(_mm256_extractf128_si256(a, 0), _mm256_extractf128_si256(b, 0));
1150 __m128i hi = _mm_max_epu32(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1));
1151 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
1152#endif
1153}
1154
1155#ifdef EIGEN_VECTORIZE_AVX2
1156template <>
1157EIGEN_STRONG_INLINE Packet8i psign(const Packet8i& a) {
1158 return _mm256_sign_epi32(_mm256_set1_epi32(1), a);
1159}
1160#endif
1161
1162// Add specializations for min/max with prescribed NaN propagation.
1163template <>
1164EIGEN_STRONG_INLINE Packet8f pmin<PropagateNumbers, Packet8f>(const Packet8f& a, const Packet8f& b) {
1165 return pminmax_propagate_numbers(a, b, pmin<Packet8f>);
1166}
1167template <>
1168EIGEN_STRONG_INLINE Packet4d pmin<PropagateNumbers, Packet4d>(const Packet4d& a, const Packet4d& b) {
1169 return pminmax_propagate_numbers(a, b, pmin<Packet4d>);
1170}
1171template <>
1172EIGEN_STRONG_INLINE Packet8f pmax<PropagateNumbers, Packet8f>(const Packet8f& a, const Packet8f& b) {
1173 return pminmax_propagate_numbers(a, b, pmax<Packet8f>);
1174}
1175template <>
1176EIGEN_STRONG_INLINE Packet4d pmax<PropagateNumbers, Packet4d>(const Packet4d& a, const Packet4d& b) {
1177 return pminmax_propagate_numbers(a, b, pmax<Packet4d>);
1178}
1179template <>
1180EIGEN_STRONG_INLINE Packet8f pmin<PropagateNaN, Packet8f>(const Packet8f& a, const Packet8f& b) {
1181 return pminmax_propagate_nan(a, b, pmin<Packet8f>);
1182}
1183template <>
1184EIGEN_STRONG_INLINE Packet4d pmin<PropagateNaN, Packet4d>(const Packet4d& a, const Packet4d& b) {
1185 return pminmax_propagate_nan(a, b, pmin<Packet4d>);
1186}
1187template <>
1188EIGEN_STRONG_INLINE Packet8f pmax<PropagateNaN, Packet8f>(const Packet8f& a, const Packet8f& b) {
1189 return pminmax_propagate_nan(a, b, pmax<Packet8f>);
1190}
1191template <>
1192EIGEN_STRONG_INLINE Packet4d pmax<PropagateNaN, Packet4d>(const Packet4d& a, const Packet4d& b) {
1193 return pminmax_propagate_nan(a, b, pmax<Packet4d>);
1194}
1195
1196template <>
1197EIGEN_STRONG_INLINE Packet8f print<Packet8f>(const Packet8f& a) {
1198 return _mm256_round_ps(a, _MM_FROUND_CUR_DIRECTION);
1199}
1200template <>
1201EIGEN_STRONG_INLINE Packet4d print<Packet4d>(const Packet4d& a) {
1202 return _mm256_round_pd(a, _MM_FROUND_CUR_DIRECTION);
1203}
1204
1205template <>
1206EIGEN_STRONG_INLINE Packet8f pceil<Packet8f>(const Packet8f& a) {
1207 return _mm256_ceil_ps(a);
1208}
1209template <>
1210EIGEN_STRONG_INLINE Packet4d pceil<Packet4d>(const Packet4d& a) {
1211 return _mm256_ceil_pd(a);
1212}
1213
1214template <>
1215EIGEN_STRONG_INLINE Packet8f pfloor<Packet8f>(const Packet8f& a) {
1216 return _mm256_floor_ps(a);
1217}
1218template <>
1219EIGEN_STRONG_INLINE Packet4d pfloor<Packet4d>(const Packet4d& a) {
1220 return _mm256_floor_pd(a);
1221}
1222
1223template <>
1224EIGEN_STRONG_INLINE Packet8f ptrunc<Packet8f>(const Packet8f& a) {
1225 return _mm256_round_ps(a, _MM_FROUND_TRUNC);
1226}
1227template <>
1228EIGEN_STRONG_INLINE Packet4d ptrunc<Packet4d>(const Packet4d& a) {
1229 return _mm256_round_pd(a, _MM_FROUND_TRUNC);
1230}
1231
1232template <>
1233EIGEN_STRONG_INLINE Packet8i ptrue<Packet8i>(const Packet8i& a) {
1234#ifdef EIGEN_VECTORIZE_AVX2
1235 // vpcmpeqd has lower latency than the more general vcmpps
1236 return _mm256_cmpeq_epi32(a, a);
1237#else
1238 const __m256 b = _mm256_castsi256_ps(a);
1239 return _mm256_castps_si256(_mm256_cmp_ps(b, b, _CMP_TRUE_UQ));
1240#endif
1241}
1242
1243template <>
1244EIGEN_STRONG_INLINE Packet8f ptrue<Packet8f>(const Packet8f& a) {
1245#ifdef EIGEN_VECTORIZE_AVX2
1246 // vpcmpeqd has lower latency than the more general vcmpps
1247 const __m256i b = _mm256_castps_si256(a);
1248 Packet8f r = _mm256_castsi256_ps(_mm256_cmpeq_epi32(b, b));
1249 EIGEN_FAST_MATH_CONSTANT_BARRIER(r);
1250 return r;
1251#else
1252 Packet8f r = _mm256_cmp_ps(a, a, _CMP_TRUE_UQ);
1253 EIGEN_FAST_MATH_CONSTANT_BARRIER(r);
1254 return r;
1255#endif
1256}
1257
1258template <>
1259EIGEN_STRONG_INLINE Packet4d ptrue<Packet4d>(const Packet4d& a) {
1260#ifdef EIGEN_VECTORIZE_AVX2
1261 // vpcmpeqq has lower latency than the more general vcmppd
1262 const __m256i b = _mm256_castpd_si256(a);
1263 Packet4d r = _mm256_castsi256_pd(_mm256_cmpeq_epi64(b, b));
1264 EIGEN_FAST_MATH_CONSTANT_BARRIER(r);
1265 return r;
1266#else
1267 Packet4d r = _mm256_cmp_pd(a, a, _CMP_TRUE_UQ);
1268 EIGEN_FAST_MATH_CONSTANT_BARRIER(r);
1269 return r;
1270#endif
1271}
1272
1273template <>
1274EIGEN_STRONG_INLINE Packet8f pand<Packet8f>(const Packet8f& a, const Packet8f& b) {
1275 return _mm256_and_ps(a, b);
1276}
1277template <>
1278EIGEN_STRONG_INLINE Packet4d pand<Packet4d>(const Packet4d& a, const Packet4d& b) {
1279 return _mm256_and_pd(a, b);
1280}
1281template <>
1282EIGEN_STRONG_INLINE Packet8i pand<Packet8i>(const Packet8i& a, const Packet8i& b) {
1283#ifdef EIGEN_VECTORIZE_AVX2
1284 return _mm256_and_si256(a, b);
1285#else
1286 return _mm256_castps_si256(_mm256_and_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b)));
1287#endif
1288}
1289template <>
1290EIGEN_STRONG_INLINE Packet8ui pand<Packet8ui>(const Packet8ui& a, const Packet8ui& b) {
1291#ifdef EIGEN_VECTORIZE_AVX2
1292 return _mm256_and_si256(a, b);
1293#else
1294 return _mm256_castps_si256(_mm256_and_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b)));
1295#endif
1296}
1297
1298template <>
1299EIGEN_STRONG_INLINE Packet8f por<Packet8f>(const Packet8f& a, const Packet8f& b) {
1300 return _mm256_or_ps(a, b);
1301}
1302template <>
1303EIGEN_STRONG_INLINE Packet4d por<Packet4d>(const Packet4d& a, const Packet4d& b) {
1304 return _mm256_or_pd(a, b);
1305}
1306template <>
1307EIGEN_STRONG_INLINE Packet8i por<Packet8i>(const Packet8i& a, const Packet8i& b) {
1308#ifdef EIGEN_VECTORIZE_AVX2
1309 return _mm256_or_si256(a, b);
1310#else
1311 return _mm256_castps_si256(_mm256_or_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b)));
1312#endif
1313}
1314template <>
1315EIGEN_STRONG_INLINE Packet8ui por<Packet8ui>(const Packet8ui& a, const Packet8ui& b) {
1316#ifdef EIGEN_VECTORIZE_AVX2
1317 return _mm256_or_si256(a, b);
1318#else
1319 return _mm256_castps_si256(_mm256_or_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b)));
1320#endif
1321}
1322
1323template <>
1324EIGEN_STRONG_INLINE Packet8f pxor<Packet8f>(const Packet8f& a, const Packet8f& b) {
1325 return _mm256_xor_ps(a, b);
1326}
1327template <>
1328EIGEN_STRONG_INLINE Packet4d pxor<Packet4d>(const Packet4d& a, const Packet4d& b) {
1329 return _mm256_xor_pd(a, b);
1330}
1331template <>
1332EIGEN_STRONG_INLINE Packet8i pxor<Packet8i>(const Packet8i& a, const Packet8i& b) {
1333#ifdef EIGEN_VECTORIZE_AVX2
1334 return _mm256_xor_si256(a, b);
1335#else
1336 return _mm256_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b)));
1337#endif
1338}
1339template <>
1340EIGEN_STRONG_INLINE Packet8ui pxor<Packet8ui>(const Packet8ui& a, const Packet8ui& b) {
1341#ifdef EIGEN_VECTORIZE_AVX2
1342 return _mm256_xor_si256(a, b);
1343#else
1344 return _mm256_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b)));
1345#endif
1346}
1347
1348template <>
1349EIGEN_STRONG_INLINE Packet8f pandnot<Packet8f>(const Packet8f& a, const Packet8f& b) {
1350 return _mm256_andnot_ps(b, a);
1351}
1352template <>
1353EIGEN_STRONG_INLINE Packet4d pandnot<Packet4d>(const Packet4d& a, const Packet4d& b) {
1354 return _mm256_andnot_pd(b, a);
1355}
1356template <>
1357EIGEN_STRONG_INLINE Packet8i pandnot<Packet8i>(const Packet8i& a, const Packet8i& b) {
1358#ifdef EIGEN_VECTORIZE_AVX2
1359 return _mm256_andnot_si256(b, a);
1360#else
1361 return _mm256_castps_si256(_mm256_andnot_ps(_mm256_castsi256_ps(b), _mm256_castsi256_ps(a)));
1362#endif
1363}
1364template <>
1365EIGEN_STRONG_INLINE Packet8ui pandnot<Packet8ui>(const Packet8ui& a, const Packet8ui& b) {
1366#ifdef EIGEN_VECTORIZE_AVX2
1367 return _mm256_andnot_si256(b, a);
1368#else
1369 return _mm256_castps_si256(_mm256_andnot_ps(_mm256_castsi256_ps(b), _mm256_castsi256_ps(a)));
1370#endif
1371}
1372
1373template <>
1374EIGEN_STRONG_INLINE Packet8ui pcmp_lt(const Packet8ui& a, const Packet8ui& b) {
1375 return pxor(pcmp_eq(a, pmax(a, b)), ptrue(a));
1376}
1377template <>
1378EIGEN_STRONG_INLINE Packet8ui pcmp_le(const Packet8ui& a, const Packet8ui& b) {
1379 return pcmp_eq(a, pmin(a, b));
1380}
1381
1382template <>
1383EIGEN_STRONG_INLINE Packet8f pround<Packet8f>(const Packet8f& a) {
1384 const Packet8f mask = pset1frombits<Packet8f>(static_cast<numext::uint32_t>(0x80000000u));
1385 const Packet8f prev0dot5 = pset1frombits<Packet8f>(static_cast<numext::uint32_t>(0x3EFFFFFFu));
1386 return _mm256_round_ps(padd(por(pand(a, mask), prev0dot5), a), _MM_FROUND_TO_ZERO);
1387}
1388template <>
1389EIGEN_STRONG_INLINE Packet4d pround<Packet4d>(const Packet4d& a) {
1390 const Packet4d mask = pset1frombits<Packet4d>(static_cast<numext::uint64_t>(0x8000000000000000ull));
1391 const Packet4d prev0dot5 = pset1frombits<Packet4d>(static_cast<numext::uint64_t>(0x3FDFFFFFFFFFFFFFull));
1392 return _mm256_round_pd(padd(por(pand(a, mask), prev0dot5), a), _MM_FROUND_TO_ZERO);
1393}
1394
1395template <>
1396EIGEN_STRONG_INLINE Packet8f pselect<Packet8f>(const Packet8f& mask, const Packet8f& a, const Packet8f& b) {
1397 return _mm256_blendv_ps(b, a, mask);
1398}
1399template <>
1400EIGEN_STRONG_INLINE Packet8i pselect<Packet8i>(const Packet8i& mask, const Packet8i& a, const Packet8i& b) {
1401 return _mm256_castps_si256(
1402 _mm256_blendv_ps(_mm256_castsi256_ps(b), _mm256_castsi256_ps(a), _mm256_castsi256_ps(mask)));
1403}
1404template <>
1405EIGEN_STRONG_INLINE Packet8ui pselect<Packet8ui>(const Packet8ui& mask, const Packet8ui& a, const Packet8ui& b) {
1406 return _mm256_castps_si256(
1407 _mm256_blendv_ps(_mm256_castsi256_ps(b), _mm256_castsi256_ps(a), _mm256_castsi256_ps(mask)));
1408}
1409
1410template <>
1411EIGEN_STRONG_INLINE Packet4d pselect<Packet4d>(const Packet4d& mask, const Packet4d& a, const Packet4d& b) {
1412 return _mm256_blendv_pd(b, a, mask);
1413}
1414
1415template <int N>
1416EIGEN_STRONG_INLINE Packet8i parithmetic_shift_right(const Packet8i& a) {
1417#ifdef EIGEN_VECTORIZE_AVX2
1418 return _mm256_srai_epi32(a, N);
1419#else
1420 __m128i lo = _mm_srai_epi32(_mm256_extractf128_si256(a, 0), N);
1421 __m128i hi = _mm_srai_epi32(_mm256_extractf128_si256(a, 1), N);
1422 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
1423#endif
1424}
1425
1426template <int N>
1427EIGEN_STRONG_INLINE Packet8i plogical_shift_right(const Packet8i& a) {
1428#ifdef EIGEN_VECTORIZE_AVX2
1429 return _mm256_srli_epi32(a, N);
1430#else
1431 __m128i lo = _mm_srli_epi32(_mm256_extractf128_si256(a, 0), N);
1432 __m128i hi = _mm_srli_epi32(_mm256_extractf128_si256(a, 1), N);
1433 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
1434#endif
1435}
1436
1437template <int N>
1438EIGEN_STRONG_INLINE Packet8i plogical_shift_left(const Packet8i& a) {
1439#ifdef EIGEN_VECTORIZE_AVX2
1440 return _mm256_slli_epi32(a, N);
1441#else
1442 __m128i lo = _mm_slli_epi32(_mm256_extractf128_si256(a, 0), N);
1443 __m128i hi = _mm_slli_epi32(_mm256_extractf128_si256(a, 1), N);
1444 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
1445#endif
1446}
1447
1448template <int N>
1449EIGEN_STRONG_INLINE Packet8ui parithmetic_shift_right(const Packet8ui& a) {
1450 return (Packet8ui)plogical_shift_right<N>((Packet8i)a);
1451}
1452template <int N>
1453EIGEN_STRONG_INLINE Packet8ui plogical_shift_right(const Packet8ui& a) {
1454 return (Packet8ui)plogical_shift_right<N>((Packet8i)a);
1455}
1456template <int N>
1457EIGEN_STRONG_INLINE Packet8ui plogical_shift_left(const Packet8ui& a) {
1458 return (Packet8ui)plogical_shift_left<N>((Packet8i)a);
1459}
1460
1461template <>
1462EIGEN_STRONG_INLINE Packet8f pload<Packet8f>(const float* from) {
1463 EIGEN_DEBUG_ALIGNED_LOAD return _mm256_load_ps(from);
1464}
1465template <>
1466EIGEN_STRONG_INLINE Packet4d pload<Packet4d>(const double* from) {
1467 EIGEN_DEBUG_ALIGNED_LOAD return _mm256_load_pd(from);
1468}
1469template <>
1470EIGEN_STRONG_INLINE Packet8i pload<Packet8i>(const int* from) {
1471 EIGEN_DEBUG_ALIGNED_LOAD return _mm256_load_si256(reinterpret_cast<const __m256i*>(from));
1472}
1473template <>
1474EIGEN_STRONG_INLINE Packet8ui pload<Packet8ui>(const uint32_t* from) {
1475 EIGEN_DEBUG_ALIGNED_LOAD return _mm256_load_si256(reinterpret_cast<const __m256i*>(from));
1476}
1477
1478template <>
1479EIGEN_STRONG_INLINE Packet8f ploadu<Packet8f>(const float* from) {
1480 EIGEN_DEBUG_UNALIGNED_LOAD return _mm256_loadu_ps(from);
1481}
1482template <>
1483EIGEN_STRONG_INLINE Packet4d ploadu<Packet4d>(const double* from) {
1484 EIGEN_DEBUG_UNALIGNED_LOAD return _mm256_loadu_pd(from);
1485}
1486template <>
1487EIGEN_STRONG_INLINE Packet8i ploadu<Packet8i>(const int* from) {
1488 EIGEN_DEBUG_UNALIGNED_LOAD return _mm256_loadu_si256(reinterpret_cast<const __m256i*>(from));
1489}
1490template <>
1491EIGEN_STRONG_INLINE Packet8ui ploadu<Packet8ui>(const uint32_t* from) {
1492 EIGEN_DEBUG_UNALIGNED_LOAD return _mm256_loadu_si256(reinterpret_cast<const __m256i*>(from));
1493}
1494
1495template <>
1496EIGEN_STRONG_INLINE Packet8f ploadu<Packet8f>(const float* from, uint8_t umask) {
1497#ifdef EIGEN_VECTORIZE_AVX512
1498 __mmask16 mask = static_cast<__mmask16>(umask & 0x00FF);
1499 EIGEN_DEBUG_UNALIGNED_LOAD return _mm512_castps512_ps256(_mm512_maskz_loadu_ps(mask, from));
1500#else
1501 Packet8i mask = _mm256_set1_epi8(static_cast<char>(umask));
1502 const Packet8i bit_mask =
1503 _mm256_set_epi32(0xffffff7f, 0xffffffbf, 0xffffffdf, 0xffffffef, 0xfffffff7, 0xfffffffb, 0xfffffffd, 0xfffffffe);
1504 mask = por<Packet8i>(mask, bit_mask);
1505 mask = pcmp_eq<Packet8i>(mask, _mm256_set1_epi32(0xffffffff));
1506 EIGEN_DEBUG_UNALIGNED_LOAD return _mm256_maskload_ps(from, mask);
1507#endif
1508}
1509
1510// Loads 4 floats from memory a returns the packet {a0, a0, a1, a1, a2, a2, a3, a3}
1511template <>
1512EIGEN_STRONG_INLINE Packet8f ploaddup<Packet8f>(const float* from) {
1513 // TODO try to find a way to avoid the need of a temporary register
1514 // Packet8f tmp = _mm256_castps128_ps256(_mm_loadu_ps(from));
1515 // tmp = _mm256_insertf128_ps(tmp, _mm_movehl_ps(_mm256_castps256_ps128(tmp),_mm256_castps256_ps128(tmp)), 1);
1516 // return _mm256_unpacklo_ps(tmp,tmp);
1517
1518 // _mm256_insertf128_ps is very slow on Haswell, thus:
1519 Packet8f tmp = _mm256_broadcast_ps((const __m128*)(const void*)from);
1520 // mimic an "inplace" permutation of the lower 128bits using a blend
1521 tmp = _mm256_blend_ps(
1522 tmp, _mm256_castps128_ps256(_mm_permute_ps(_mm256_castps256_ps128(tmp), _MM_SHUFFLE(1, 0, 1, 0))), 15);
1523 // then we can perform a consistent permutation on the global register to get everything in shape:
1524 return _mm256_permute_ps(tmp, _MM_SHUFFLE(3, 3, 2, 2));
1525}
1526// Loads 2 doubles from memory a returns the packet {a0, a0, a1, a1}
1527template <>
1528EIGEN_STRONG_INLINE Packet4d ploaddup<Packet4d>(const double* from) {
1529 Packet4d tmp = _mm256_broadcast_pd((const __m128d*)(const void*)from);
1530 return _mm256_permute_pd(tmp, 3 << 2);
1531}
1532// Loads 4 integers from memory a returns the packet {a0, a0, a1, a1, a2, a2, a3, a3}
1533template <>
1534EIGEN_STRONG_INLINE Packet8i ploaddup<Packet8i>(const int* from) {
1535#ifdef EIGEN_VECTORIZE_AVX2
1536 const Packet8i a = _mm256_castsi128_si256(ploadu<Packet4i>(from));
1537 return _mm256_permutevar8x32_epi32(a, _mm256_setr_epi32(0, 0, 1, 1, 2, 2, 3, 3));
1538#else
1539 __m256 tmp = _mm256_broadcast_ps((const __m128*)(const void*)from);
1540 // mimic an "inplace" permutation of the lower 128bits using a blend
1541 tmp = _mm256_blend_ps(
1542 tmp, _mm256_castps128_ps256(_mm_permute_ps(_mm256_castps256_ps128(tmp), _MM_SHUFFLE(1, 0, 1, 0))), 15);
1543 // then we can perform a consistent permutation on the global register to get everything in shape:
1544 return _mm256_castps_si256(_mm256_permute_ps(tmp, _MM_SHUFFLE(3, 3, 2, 2)));
1545#endif
1546}
1547template <>
1548EIGEN_STRONG_INLINE Packet8ui ploaddup<Packet8ui>(const uint32_t* from) {
1549#ifdef EIGEN_VECTORIZE_AVX2
1550 const Packet8ui a = _mm256_castsi128_si256(ploadu<Packet4ui>(from));
1551 return _mm256_permutevar8x32_epi32(a, _mm256_setr_epi32(0, 0, 1, 1, 2, 2, 3, 3));
1552#else
1553 __m256 tmp = _mm256_broadcast_ps((const __m128*)(const void*)from);
1554 // mimic an "inplace" permutation of the lower 128bits using a blend
1555 tmp = _mm256_blend_ps(
1556 tmp, _mm256_castps128_ps256(_mm_permute_ps(_mm256_castps256_ps128(tmp), _MM_SHUFFLE(1, 0, 1, 0))), 15);
1557 // then we can perform a consistent permutation on the global register to get
1558 // everything in shape:
1559 return _mm256_castps_si256(_mm256_permute_ps(tmp, _MM_SHUFFLE(3, 3, 2, 2)));
1560#endif
1561}
1562
1563// Loads 2 floats from memory a returns the packet {a0, a0, a0, a0, a1, a1, a1, a1}
1564template <>
1565EIGEN_STRONG_INLINE Packet8f ploadquad<Packet8f>(const float* from) {
1566 Packet8f tmp = _mm256_castps128_ps256(_mm_broadcast_ss(from));
1567 return _mm256_insertf128_ps(tmp, _mm_broadcast_ss(from + 1), 1);
1568}
1569template <>
1570EIGEN_STRONG_INLINE Packet8i ploadquad<Packet8i>(const int* from) {
1571 return _mm256_insertf128_si256(_mm256_set1_epi32(*from), _mm_set1_epi32(*(from + 1)), 1);
1572}
1573template <>
1574EIGEN_STRONG_INLINE Packet8ui ploadquad<Packet8ui>(const uint32_t* from) {
1575 return _mm256_insertf128_si256(_mm256_set1_epi32(*from), _mm_set1_epi32(*(from + 1)), 1);
1576}
1577
1578template <>
1579EIGEN_STRONG_INLINE void pstore<float>(float* to, const Packet8f& from) {
1580 EIGEN_DEBUG_ALIGNED_STORE _mm256_store_ps(to, from);
1581}
1582template <>
1583EIGEN_STRONG_INLINE void pstore<double>(double* to, const Packet4d& from) {
1584 EIGEN_DEBUG_ALIGNED_STORE _mm256_store_pd(to, from);
1585}
1586template <>
1587EIGEN_STRONG_INLINE void pstore<int>(int* to, const Packet8i& from) {
1588 EIGEN_DEBUG_ALIGNED_STORE _mm256_store_si256(reinterpret_cast<__m256i*>(to), from);
1589}
1590template <>
1591EIGEN_STRONG_INLINE void pstore<uint32_t>(uint32_t* to, const Packet8ui& from) {
1592 EIGEN_DEBUG_ALIGNED_STORE _mm256_store_si256(reinterpret_cast<__m256i*>(to), from);
1593}
1594
1595template <>
1596EIGEN_STRONG_INLINE void pstoreu<float>(float* to, const Packet8f& from) {
1597 EIGEN_DEBUG_UNALIGNED_STORE _mm256_storeu_ps(to, from);
1598}
1599template <>
1600EIGEN_STRONG_INLINE void pstoreu<double>(double* to, const Packet4d& from) {
1601 EIGEN_DEBUG_UNALIGNED_STORE _mm256_storeu_pd(to, from);
1602}
1603template <>
1604EIGEN_STRONG_INLINE void pstoreu<int>(int* to, const Packet8i& from) {
1605 EIGEN_DEBUG_UNALIGNED_STORE _mm256_storeu_si256(reinterpret_cast<__m256i*>(to), from);
1606}
1607template <>
1608EIGEN_STRONG_INLINE void pstoreu<uint32_t>(uint32_t* to, const Packet8ui& from) {
1609 EIGEN_DEBUG_UNALIGNED_STORE _mm256_storeu_si256(reinterpret_cast<__m256i*>(to), from);
1610}
1611
1612template <>
1613EIGEN_STRONG_INLINE void pstoreu<float>(float* to, const Packet8f& from, uint8_t umask) {
1614#ifdef EIGEN_VECTORIZE_AVX512
1615 __mmask16 mask = static_cast<__mmask16>(umask & 0x00FF);
1616 EIGEN_DEBUG_UNALIGNED_STORE _mm512_mask_storeu_ps(to, mask, _mm512_castps256_ps512(from));
1617#else
1618 Packet8i mask = _mm256_set1_epi8(static_cast<char>(umask));
1619 const Packet8i bit_mask =
1620 _mm256_set_epi32(0x7f7f7f7f, 0xbfbfbfbf, 0xdfdfdfdf, 0xefefefef, 0xf7f7f7f7, 0xfbfbfbfb, 0xfdfdfdfd, 0xfefefefe);
1621 mask = por<Packet8i>(mask, bit_mask);
1622 mask = pcmp_eq<Packet8i>(mask, _mm256_set1_epi32(0xffffffff));
1623#if EIGEN_COMP_MSVC
1624 // MSVC sometimes seems to use a bogus mask with maskstore.
1625 const __m256i ifrom = _mm256_castps_si256(from);
1626 EIGEN_DEBUG_UNALIGNED_STORE _mm_maskmoveu_si128(_mm256_extractf128_si256(ifrom, 0), _mm256_extractf128_si256(mask, 0),
1627 reinterpret_cast<char*>(to));
1628 EIGEN_DEBUG_UNALIGNED_STORE _mm_maskmoveu_si128(_mm256_extractf128_si256(ifrom, 1), _mm256_extractf128_si256(mask, 1),
1629 reinterpret_cast<char*>(to + 4));
1630#else
1631 EIGEN_DEBUG_UNALIGNED_STORE _mm256_maskstore_ps(to, mask, from);
1632#endif
1633#endif
1634}
1635
1636// NOTE: leverage _mm256_i32gather_ps and _mm256_i32gather_pd if AVX2 instructions are available
1637// NOTE: for the record the following seems to be slower: return _mm256_i32gather_ps(from, _mm256_set1_epi32(stride),
1638// 4);
1639template <>
1640EIGEN_DEVICE_FUNC inline Packet8f pgather<float, Packet8f>(const float* from, Index stride) {
1641 if (stride == 2) {
1642#ifdef EIGEN_VECTORIZE_AVX2
1643 // Both loads stay within from[0..14], including when from points to an imaginary component.
1644 const Packet8f low = _mm256_loadu_ps(from);
1645 const Packet8f high = _mm256_loadu_ps(from + 7);
1646 const Packet8f interleaved = _mm256_shuffle_ps(low, high, _MM_SHUFFLE(3, 1, 2, 0));
1647 return _mm256_castpd_ps(_mm256_permute4x64_pd(_mm256_castps_pd(interleaved), _MM_SHUFFLE(3, 1, 2, 0)));
1648#else
1649 const Packet4f low = pgather<float, Packet4f>(from, 2);
1650 const Packet4f high = pgather<float, Packet4f>(from + 8, 2);
1651 return _mm256_insertf128_ps(_mm256_castps128_ps256(low), high, 1);
1652#endif
1653 }
1654 return _mm256_set_ps(from[7 * stride], from[6 * stride], from[5 * stride], from[4 * stride], from[3 * stride],
1655 from[2 * stride], from[1 * stride], from[0 * stride]);
1656}
1657template <>
1658EIGEN_DEVICE_FUNC inline Packet4d pgather<double, Packet4d>(const double* from, Index stride) {
1659#ifdef EIGEN_VECTORIZE_AVX2
1660 if (stride == 2) {
1661 const Packet4d low = _mm256_loadu_pd(from);
1662 const Packet4d high = _mm256_loadu_pd(from + 3);
1663 const Packet4d interleaved = _mm256_shuffle_pd(low, high, 0xa);
1664 return _mm256_permute4x64_pd(interleaved, _MM_SHUFFLE(3, 1, 2, 0));
1665 }
1666#endif
1667 return _mm256_set_pd(from[3 * stride], from[2 * stride], from[1 * stride], from[0 * stride]);
1668}
1669template <>
1670EIGEN_DEVICE_FUNC inline Packet8i pgather<int, Packet8i>(const int* from, Index stride) {
1671 return _mm256_set_epi32(from[7 * stride], from[6 * stride], from[5 * stride], from[4 * stride], from[3 * stride],
1672 from[2 * stride], from[1 * stride], from[0 * stride]);
1673}
1674template <>
1675EIGEN_DEVICE_FUNC inline Packet8ui pgather<uint32_t, Packet8ui>(const uint32_t* from, Index stride) {
1676 return (Packet8ui)pgather<int, Packet8i>((int*)from, stride);
1677}
1678
1679template <>
1680EIGEN_DEVICE_FUNC inline void pscatter<float, Packet8f>(float* to, const Packet8f& from, Index stride) {
1681 __m128 low = _mm256_extractf128_ps(from, 0);
1682 to[stride * 0] = _mm_cvtss_f32(low);
1683 to[stride * 1] = _mm_cvtss_f32(_mm_shuffle_ps(low, low, 1));
1684 to[stride * 2] = _mm_cvtss_f32(_mm_shuffle_ps(low, low, 2));
1685 to[stride * 3] = _mm_cvtss_f32(_mm_shuffle_ps(low, low, 3));
1686
1687 __m128 high = _mm256_extractf128_ps(from, 1);
1688 to[stride * 4] = _mm_cvtss_f32(high);
1689 to[stride * 5] = _mm_cvtss_f32(_mm_shuffle_ps(high, high, 1));
1690 to[stride * 6] = _mm_cvtss_f32(_mm_shuffle_ps(high, high, 2));
1691 to[stride * 7] = _mm_cvtss_f32(_mm_shuffle_ps(high, high, 3));
1692}
1693template <>
1694EIGEN_DEVICE_FUNC inline void pscatter<double, Packet4d>(double* to, const Packet4d& from, Index stride) {
1695 __m128d low = _mm256_extractf128_pd(from, 0);
1696 to[stride * 0] = _mm_cvtsd_f64(low);
1697 to[stride * 1] = _mm_cvtsd_f64(_mm_shuffle_pd(low, low, 1));
1698 __m128d high = _mm256_extractf128_pd(from, 1);
1699 to[stride * 2] = _mm_cvtsd_f64(high);
1700 to[stride * 3] = _mm_cvtsd_f64(_mm_shuffle_pd(high, high, 1));
1701}
1702template <>
1703EIGEN_DEVICE_FUNC inline void pscatter<int, Packet8i>(int* to, const Packet8i& from, Index stride) {
1704 __m128i low = _mm256_extractf128_si256(from, 0);
1705 to[stride * 0] = _mm_extract_epi32(low, 0);
1706 to[stride * 1] = _mm_extract_epi32(low, 1);
1707 to[stride * 2] = _mm_extract_epi32(low, 2);
1708 to[stride * 3] = _mm_extract_epi32(low, 3);
1709
1710 __m128i high = _mm256_extractf128_si256(from, 1);
1711 to[stride * 4] = _mm_extract_epi32(high, 0);
1712 to[stride * 5] = _mm_extract_epi32(high, 1);
1713 to[stride * 6] = _mm_extract_epi32(high, 2);
1714 to[stride * 7] = _mm_extract_epi32(high, 3);
1715}
1716template <>
1717EIGEN_DEVICE_FUNC inline void pscatter<uint32_t, Packet8ui>(uint32_t* to, const Packet8ui& from, Index stride) {
1718 pscatter<int, Packet8i>((int*)to, (Packet8i)from, stride);
1719}
1720
1721template <>
1722EIGEN_STRONG_INLINE void pstore1<Packet8f>(float* to, const float& a) {
1723 Packet8f pa = pset1<Packet8f>(a);
1724 pstore(to, pa);
1725}
1726template <>
1727EIGEN_STRONG_INLINE void pstore1<Packet4d>(double* to, const double& a) {
1728 Packet4d pa = pset1<Packet4d>(a);
1729 pstore(to, pa);
1730}
1731template <>
1732EIGEN_STRONG_INLINE void pstore1<Packet8i>(int* to, const int& a) {
1733 Packet8i pa = pset1<Packet8i>(a);
1734 pstore(to, pa);
1735}
1736
1737#ifndef EIGEN_VECTORIZE_AVX512
1738template <>
1739EIGEN_STRONG_INLINE void prefetch<float>(const float* addr) {
1740 _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0);
1741}
1742template <>
1743EIGEN_STRONG_INLINE void prefetch<double>(const double* addr) {
1744 _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0);
1745}
1746template <>
1747EIGEN_STRONG_INLINE void prefetch<int>(const int* addr) {
1748 _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0);
1749}
1750template <>
1751EIGEN_STRONG_INLINE void prefetch<uint32_t>(const uint32_t* addr) {
1752 _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0);
1753}
1754#endif
1755
1756template <>
1757EIGEN_STRONG_INLINE float pfirst<Packet8f>(const Packet8f& a) {
1758 return _mm_cvtss_f32(_mm256_castps256_ps128(a));
1759}
1760template <>
1761EIGEN_STRONG_INLINE double pfirst<Packet4d>(const Packet4d& a) {
1762 return _mm_cvtsd_f64(_mm256_castpd256_pd128(a));
1763}
1764template <>
1765EIGEN_STRONG_INLINE int pfirst<Packet8i>(const Packet8i& a) {
1766 return _mm_cvtsi128_si32(_mm256_castsi256_si128(a));
1767}
1768template <>
1769EIGEN_STRONG_INLINE uint32_t pfirst<Packet8ui>(const Packet8ui& a) {
1770 return numext::bit_cast<uint32_t>(_mm_cvtsi128_si32(_mm256_castsi256_si128(a)));
1771}
1772
1773template <>
1774EIGEN_STRONG_INLINE Packet8f preverse(const Packet8f& a) {
1775 __m256 tmp = _mm256_shuffle_ps(a, a, 0x1b);
1776 return _mm256_permute2f128_ps(tmp, tmp, 1);
1777}
1778template <>
1779EIGEN_STRONG_INLINE Packet4d preverse(const Packet4d& a) {
1780 __m256d tmp = _mm256_shuffle_pd(a, a, 5);
1781 return _mm256_permute2f128_pd(tmp, tmp, 1);
1782}
1783template <>
1784EIGEN_STRONG_INLINE Packet8i preverse(const Packet8i& a) {
1785 return _mm256_castps_si256(preverse(_mm256_castsi256_ps(a)));
1786}
1787template <>
1788EIGEN_STRONG_INLINE Packet8ui preverse(const Packet8ui& a) {
1789 return _mm256_castps_si256(preverse(_mm256_castsi256_ps(a)));
1790}
1791
1792#ifdef EIGEN_VECTORIZE_AVX2
1793template <>
1794EIGEN_STRONG_INLINE Packet4l preverse(const Packet4l& a) {
1795 return _mm256_castpd_si256(preverse(_mm256_castsi256_pd(a)));
1796}
1797template <>
1798EIGEN_STRONG_INLINE Packet4ul preverse(const Packet4ul& a) {
1799 return _mm256_castpd_si256(preverse(_mm256_castsi256_pd(a)));
1800}
1801#endif
1802
1803// pabs should be ok
1804template <>
1805EIGEN_STRONG_INLINE Packet8f pabs(const Packet8f& a) {
1806 const Packet8f mask = _mm256_castsi256_ps(_mm256_set1_epi32(0x7FFFFFFF));
1807 return _mm256_and_ps(a, mask);
1808}
1809template <>
1810EIGEN_STRONG_INLINE Packet4d pabs(const Packet4d& a) {
1811 const Packet4d mask = _mm256_castsi256_pd(_mm256_set1_epi64x(0x7FFFFFFFFFFFFFFF));
1812 return _mm256_and_pd(a, mask);
1813}
1814template <>
1815EIGEN_STRONG_INLINE Packet8i pabs(const Packet8i& a) {
1816#ifdef EIGEN_VECTORIZE_AVX2
1817 return _mm256_abs_epi32(a);
1818#else
1819 __m128i lo = _mm_abs_epi32(_mm256_extractf128_si256(a, 0));
1820 __m128i hi = _mm_abs_epi32(_mm256_extractf128_si256(a, 1));
1821 return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1);
1822#endif
1823}
1824#ifndef EIGEN_VECTORIZE_AVX512FP16
1825template <>
1826EIGEN_STRONG_INLINE Packet8h psignbit(const Packet8h& a) {
1827 return _mm_cmpgt_epi16(_mm_setzero_si128(), a);
1828}
1829#endif // EIGEN_VECTORIZE_AVX512FP16
1830
1831template <>
1832EIGEN_STRONG_INLINE Packet8bf psignbit(const Packet8bf& a) {
1833 return _mm_cmpgt_epi16(_mm_setzero_si128(), a);
1834}
1835template <>
1836EIGEN_STRONG_INLINE Packet8f psignbit(const Packet8f& a) {
1837#ifdef EIGEN_VECTORIZE_AVX2
1838 return _mm256_castsi256_ps(_mm256_cmpgt_epi32(_mm256_setzero_si256(), _mm256_castps_si256(a)));
1839#else
1840 return _mm256_castsi256_ps(parithmetic_shift_right<31>(Packet8i(_mm256_castps_si256(a))));
1841#endif
1842}
1843#ifdef EIGEN_VECTORIZE_AVX2
1844template <>
1845EIGEN_STRONG_INLINE Packet4d psignbit(const Packet4d& a) {
1846 return _mm256_castsi256_pd(_mm256_cmpgt_epi64(_mm256_setzero_si256(), _mm256_castpd_si256(a)));
1847}
1848#endif
1849
1850template <>
1851EIGEN_STRONG_INLINE Packet8f pfrexp<Packet8f>(const Packet8f& a, Packet8f& exponent) {
1852 return pfrexp_generic(a, exponent);
1853}
1854
1855// Extract exponent without existence of Packet4l.
1856template <>
1857EIGEN_STRONG_INLINE Packet4d pfrexp_generic_get_biased_exponent(const Packet4d& a) {
1858 const Packet4d cst_exp_mask = pset1frombits<Packet4d>(static_cast<uint64_t>(0x7ff0000000000000ull));
1859 __m256i a_expo = _mm256_castpd_si256(pand(a, cst_exp_mask));
1860#ifdef EIGEN_VECTORIZE_AVX2
1861 a_expo = _mm256_srli_epi64(a_expo, 52);
1862 __m128i lo = _mm256_extractf128_si256(a_expo, 0);
1863 __m128i hi = _mm256_extractf128_si256(a_expo, 1);
1864#else
1865 __m128i lo = _mm256_extractf128_si256(a_expo, 0);
1866 __m128i hi = _mm256_extractf128_si256(a_expo, 1);
1867 lo = _mm_srli_epi64(lo, 52);
1868 hi = _mm_srli_epi64(hi, 52);
1869#endif
1870 Packet2d exponent_lo = _mm_cvtepi32_pd(vec4i_swizzle1(lo, 0, 2, 1, 3));
1871 Packet2d exponent_hi = _mm_cvtepi32_pd(vec4i_swizzle1(hi, 0, 2, 1, 3));
1872 Packet4d exponent = _mm256_insertf128_pd(_mm256_setzero_pd(), exponent_lo, 0);
1873 exponent = _mm256_insertf128_pd(exponent, exponent_hi, 1);
1874 return exponent;
1875}
1876
1877template <>
1878EIGEN_STRONG_INLINE Packet4d pfrexp<Packet4d>(const Packet4d& a, Packet4d& exponent) {
1879 return pfrexp_generic(a, exponent);
1880}
1881
1882#ifndef EIGEN_VECTORIZE_AVX2
1883namespace unary_pow {
1884// The exponent-bit operations the integer-exponent pow needs on Packet4d, likewise without Packet4l: AVX has no
1885// 256-bit integer shift or subtract, but SSE2's 128-bit ones, present on every x86-64 target, suffice. Split the
1886// bit pattern into its two 128-bit halves, operate on each with SSE2, and reassemble.
1887template <>
1888EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet4d exponent_bits_shift_right<Packet4d>(const Packet4d& bits) {
1889 __m256i i = _mm256_castpd_si256(bits);
1890 __m128i lo = _mm_srli_epi64(_mm256_extractf128_si256(i, 0), 52);
1891 __m128i hi = _mm_srli_epi64(_mm256_extractf128_si256(i, 1), 52);
1892 return _mm256_castsi256_pd(_mm256_insertf128_si256(_mm256_castsi128_si256(lo), hi, 1));
1893}
1894template <>
1895EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet4d exponent_bits_sub<Packet4d>(const Packet4d& a_bits,
1896 const Packet4d& b_bits) {
1897 __m256i ai = _mm256_castpd_si256(a_bits);
1898 __m256i bi = _mm256_castpd_si256(b_bits);
1899 __m128i lo = _mm_sub_epi64(_mm256_extractf128_si256(ai, 0), _mm256_extractf128_si256(bi, 0));
1900 __m128i hi = _mm_sub_epi64(_mm256_extractf128_si256(ai, 1), _mm256_extractf128_si256(bi, 1));
1901 return _mm256_castsi256_pd(_mm256_insertf128_si256(_mm256_castsi128_si256(lo), hi, 1));
1902}
1903template <>
1904struct has_exponent_bit_ops<Packet4d> : true_type {};
1905} // namespace unary_pow
1906#endif
1907
1908template <>
1909EIGEN_STRONG_INLINE Packet8f pldexp<Packet8f>(const Packet8f& a, const Packet8f& exponent) {
1910 return pldexp_generic(a, exponent);
1911}
1912
1913// Build 2^k as Packet4d from a Packet4i holding the biased int32 exponent in
1914// each lane, shifted by Shift: 52 for the biased exponent, 51 for twice it.
1915// AVX2 has a single-instruction widen+shift path; AVX-only must split the
1916// 128-bit input into two halves, widen+shift each separately with SSE
1917// intrinsics, and reassemble with vinsertf128.
1918template <int Shift = 52>
1919EIGEN_STRONG_INLINE Packet4d pldexp_avx_pow2_from_biased(const Packet4i& biased) {
1920#ifdef EIGEN_VECTORIZE_AVX2
1921 return _mm256_castsi256_pd(_mm256_slli_epi64(_mm256_cvtepi32_epi64(biased), Shift));
1922#else
1923 __m128i lo = _mm_cvtepi32_epi64(biased); // SSE4.1: lower 2 int32 -> 2 int64
1924 __m128i hi = _mm_cvtepi32_epi64(_mm_unpackhi_epi64(biased, biased)); // upper 2 int32 -> 2 int64
1925 lo = _mm_slli_epi64(lo, Shift);
1926 hi = _mm_slli_epi64(hi, Shift);
1927 return _mm256_castsi256_pd(_mm256_insertf128_si256(_mm256_castsi128_si256(lo), hi, 1));
1928#endif
1929}
1930
1931template <>
1932EIGEN_STRONG_INLINE Packet4d pldexp<Packet4d>(const Packet4d& a, const Packet4d& exponent) {
1933 // Clamp exponent to [-2099, 2099]
1934 const Packet4d max_exponent = pset1<Packet4d>(2099.0);
1935 const Packet4i e = _mm256_cvtpd_epi32(pmin(pmax(exponent, pnegate(max_exponent)), max_exponent));
1936
1937 // The single-rounding split of pldexp_generic.
1938 const Packet4i bias = pset1<Packet4i>(1023);
1939 const Packet4i b = pmin(pmax(e, pset1<Packet4i>(-1022)), pset1<Packet4i>(1022));
1940 const Packet4i t = pandnot(psub(e, b), pset1<Packet4i>(1)); // even
1941 const Packet4d c1 = pldexp_avx_pow2_from_biased<51>(padd(t, padd(bias, bias))); // 2^(t/2)
1942 const Packet4d c2 = pldexp_avx_pow2_from_biased(padd(psub(e, t), bias)); // 2^(e-t)
1943
1944 return pldexp_apply_factors(a, c1, c2); // a * 2^e
1945}
1946
1947template <>
1948EIGEN_STRONG_INLINE Packet4d pldexp_fast<Packet4d>(const Packet4d& a, const Packet4d& exponent) {
1949 // Clamp exponent to [-1024, 1024]
1950 const Packet4d min_exponent = pset1<Packet4d>(-1023.0);
1951 const Packet4d max_exponent = pset1<Packet4d>(1024.0);
1952 const Packet4i e = _mm256_cvtpd_epi32(pmin(pmax(exponent, min_exponent), max_exponent));
1953 const Packet4i bias = pset1<Packet4i>(1023);
1954
1955 return pmul(a, pldexp_avx_pow2_from_biased(padd(e, bias))); // a * 2^e
1956}
1957
1958template <>
1959EIGEN_STRONG_INLINE Packet4f predux_half<Packet8f>(const Packet8f& a) {
1960 return _mm_add_ps(_mm256_castps256_ps128(a), _mm256_extractf128_ps(a, 1));
1961}
1962template <>
1963EIGEN_STRONG_INLINE Packet4i predux_half<Packet8i>(const Packet8i& a) {
1964 return _mm_add_epi32(_mm256_castsi256_si128(a), _mm256_extractf128_si256(a, 1));
1965}
1966template <>
1967EIGEN_STRONG_INLINE Packet4ui predux_half<Packet8ui>(const Packet8ui& a) {
1968 return _mm_add_epi32(_mm256_castsi256_si128(a), _mm256_extractf128_si256(a, 1));
1969}
1970
1971EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet8f, 8>& kernel) {
1972 __m256 T0 = _mm256_unpacklo_ps(kernel.packet[0], kernel.packet[1]);
1973 __m256 T1 = _mm256_unpackhi_ps(kernel.packet[0], kernel.packet[1]);
1974 __m256 T2 = _mm256_unpacklo_ps(kernel.packet[2], kernel.packet[3]);
1975 __m256 T3 = _mm256_unpackhi_ps(kernel.packet[2], kernel.packet[3]);
1976 __m256 T4 = _mm256_unpacklo_ps(kernel.packet[4], kernel.packet[5]);
1977 __m256 T5 = _mm256_unpackhi_ps(kernel.packet[4], kernel.packet[5]);
1978 __m256 T6 = _mm256_unpacklo_ps(kernel.packet[6], kernel.packet[7]);
1979 __m256 T7 = _mm256_unpackhi_ps(kernel.packet[6], kernel.packet[7]);
1980 __m256 S0 = _mm256_shuffle_ps(T0, T2, _MM_SHUFFLE(1, 0, 1, 0));
1981 __m256 S1 = _mm256_shuffle_ps(T0, T2, _MM_SHUFFLE(3, 2, 3, 2));
1982 __m256 S2 = _mm256_shuffle_ps(T1, T3, _MM_SHUFFLE(1, 0, 1, 0));
1983 __m256 S3 = _mm256_shuffle_ps(T1, T3, _MM_SHUFFLE(3, 2, 3, 2));
1984 __m256 S4 = _mm256_shuffle_ps(T4, T6, _MM_SHUFFLE(1, 0, 1, 0));
1985 __m256 S5 = _mm256_shuffle_ps(T4, T6, _MM_SHUFFLE(3, 2, 3, 2));
1986 __m256 S6 = _mm256_shuffle_ps(T5, T7, _MM_SHUFFLE(1, 0, 1, 0));
1987 __m256 S7 = _mm256_shuffle_ps(T5, T7, _MM_SHUFFLE(3, 2, 3, 2));
1988 kernel.packet[0] = _mm256_permute2f128_ps(S0, S4, 0x20);
1989 kernel.packet[1] = _mm256_permute2f128_ps(S1, S5, 0x20);
1990 kernel.packet[2] = _mm256_permute2f128_ps(S2, S6, 0x20);
1991 kernel.packet[3] = _mm256_permute2f128_ps(S3, S7, 0x20);
1992 kernel.packet[4] = _mm256_permute2f128_ps(S0, S4, 0x31);
1993 kernel.packet[5] = _mm256_permute2f128_ps(S1, S5, 0x31);
1994 kernel.packet[6] = _mm256_permute2f128_ps(S2, S6, 0x31);
1995 kernel.packet[7] = _mm256_permute2f128_ps(S3, S7, 0x31);
1996}
1997
1998EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet8f, 4>& kernel) {
1999 __m256 T0 = _mm256_unpacklo_ps(kernel.packet[0], kernel.packet[1]);
2000 __m256 T1 = _mm256_unpackhi_ps(kernel.packet[0], kernel.packet[1]);
2001 __m256 T2 = _mm256_unpacklo_ps(kernel.packet[2], kernel.packet[3]);
2002 __m256 T3 = _mm256_unpackhi_ps(kernel.packet[2], kernel.packet[3]);
2003
2004 __m256 S0 = _mm256_shuffle_ps(T0, T2, _MM_SHUFFLE(1, 0, 1, 0));
2005 __m256 S1 = _mm256_shuffle_ps(T0, T2, _MM_SHUFFLE(3, 2, 3, 2));
2006 __m256 S2 = _mm256_shuffle_ps(T1, T3, _MM_SHUFFLE(1, 0, 1, 0));
2007 __m256 S3 = _mm256_shuffle_ps(T1, T3, _MM_SHUFFLE(3, 2, 3, 2));
2008
2009 kernel.packet[0] = _mm256_permute2f128_ps(S0, S1, 0x20);
2010 kernel.packet[1] = _mm256_permute2f128_ps(S2, S3, 0x20);
2011 kernel.packet[2] = _mm256_permute2f128_ps(S0, S1, 0x31);
2012 kernel.packet[3] = _mm256_permute2f128_ps(S2, S3, 0x31);
2013}
2014
2015#define MM256_SHUFFLE_EPI32(A, B, M) \
2016 _mm256_castps_si256(_mm256_shuffle_ps(_mm256_castsi256_ps(A), _mm256_castsi256_ps(B), M))
2017
2018#ifndef EIGEN_VECTORIZE_AVX2
2019#define MM256_UNPACKLO_EPI32(A, B) \
2020 _mm256_castps_si256(_mm256_unpacklo_ps(_mm256_castsi256_ps(A), _mm256_castsi256_ps(B)))
2021#define MM256_UNPACKHI_EPI32(A, B) \
2022 _mm256_castps_si256(_mm256_unpackhi_ps(_mm256_castsi256_ps(A), _mm256_castsi256_ps(B)))
2023#else
2024#define MM256_UNPACKLO_EPI32(A, B) _mm256_unpacklo_epi32(A, B)
2025#define MM256_UNPACKHI_EPI32(A, B) _mm256_unpackhi_epi32(A, B)
2026#endif
2027
2028EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet8i, 8>& kernel) {
2029 __m256i T0 = MM256_UNPACKLO_EPI32(kernel.packet[0], kernel.packet[1]);
2030 __m256i T1 = MM256_UNPACKHI_EPI32(kernel.packet[0], kernel.packet[1]);
2031 __m256i T2 = MM256_UNPACKLO_EPI32(kernel.packet[2], kernel.packet[3]);
2032 __m256i T3 = MM256_UNPACKHI_EPI32(kernel.packet[2], kernel.packet[3]);
2033 __m256i T4 = MM256_UNPACKLO_EPI32(kernel.packet[4], kernel.packet[5]);
2034 __m256i T5 = MM256_UNPACKHI_EPI32(kernel.packet[4], kernel.packet[5]);
2035 __m256i T6 = MM256_UNPACKLO_EPI32(kernel.packet[6], kernel.packet[7]);
2036 __m256i T7 = MM256_UNPACKHI_EPI32(kernel.packet[6], kernel.packet[7]);
2037 __m256i S0 = MM256_SHUFFLE_EPI32(T0, T2, _MM_SHUFFLE(1, 0, 1, 0));
2038 __m256i S1 = MM256_SHUFFLE_EPI32(T0, T2, _MM_SHUFFLE(3, 2, 3, 2));
2039 __m256i S2 = MM256_SHUFFLE_EPI32(T1, T3, _MM_SHUFFLE(1, 0, 1, 0));
2040 __m256i S3 = MM256_SHUFFLE_EPI32(T1, T3, _MM_SHUFFLE(3, 2, 3, 2));
2041 __m256i S4 = MM256_SHUFFLE_EPI32(T4, T6, _MM_SHUFFLE(1, 0, 1, 0));
2042 __m256i S5 = MM256_SHUFFLE_EPI32(T4, T6, _MM_SHUFFLE(3, 2, 3, 2));
2043 __m256i S6 = MM256_SHUFFLE_EPI32(T5, T7, _MM_SHUFFLE(1, 0, 1, 0));
2044 __m256i S7 = MM256_SHUFFLE_EPI32(T5, T7, _MM_SHUFFLE(3, 2, 3, 2));
2045 kernel.packet[0] = _mm256_permute2f128_si256(S0, S4, 0x20);
2046 kernel.packet[1] = _mm256_permute2f128_si256(S1, S5, 0x20);
2047 kernel.packet[2] = _mm256_permute2f128_si256(S2, S6, 0x20);
2048 kernel.packet[3] = _mm256_permute2f128_si256(S3, S7, 0x20);
2049 kernel.packet[4] = _mm256_permute2f128_si256(S0, S4, 0x31);
2050 kernel.packet[5] = _mm256_permute2f128_si256(S1, S5, 0x31);
2051 kernel.packet[6] = _mm256_permute2f128_si256(S2, S6, 0x31);
2052 kernel.packet[7] = _mm256_permute2f128_si256(S3, S7, 0x31);
2053}
2054EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet8ui, 8>& kernel) {
2055 ptranspose((PacketBlock<Packet8i, 8>&)kernel);
2056}
2057
2058EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet8i, 4>& kernel) {
2059 __m256i T0 = MM256_UNPACKLO_EPI32(kernel.packet[0], kernel.packet[1]);
2060 __m256i T1 = MM256_UNPACKHI_EPI32(kernel.packet[0], kernel.packet[1]);
2061 __m256i T2 = MM256_UNPACKLO_EPI32(kernel.packet[2], kernel.packet[3]);
2062 __m256i T3 = MM256_UNPACKHI_EPI32(kernel.packet[2], kernel.packet[3]);
2063
2064 __m256i S0 = MM256_SHUFFLE_EPI32(T0, T2, _MM_SHUFFLE(1, 0, 1, 0));
2065 __m256i S1 = MM256_SHUFFLE_EPI32(T0, T2, _MM_SHUFFLE(3, 2, 3, 2));
2066 __m256i S2 = MM256_SHUFFLE_EPI32(T1, T3, _MM_SHUFFLE(1, 0, 1, 0));
2067 __m256i S3 = MM256_SHUFFLE_EPI32(T1, T3, _MM_SHUFFLE(3, 2, 3, 2));
2068
2069 kernel.packet[0] = _mm256_permute2f128_si256(S0, S1, 0x20);
2070 kernel.packet[1] = _mm256_permute2f128_si256(S2, S3, 0x20);
2071 kernel.packet[2] = _mm256_permute2f128_si256(S0, S1, 0x31);
2072 kernel.packet[3] = _mm256_permute2f128_si256(S2, S3, 0x31);
2073}
2074EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet8ui, 4>& kernel) {
2075 ptranspose((PacketBlock<Packet8i, 4>&)kernel);
2076}
2077
2078EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet4d, 4>& kernel) {
2079 __m256d T0 = _mm256_shuffle_pd(kernel.packet[0], kernel.packet[1], 15);
2080 __m256d T1 = _mm256_shuffle_pd(kernel.packet[0], kernel.packet[1], 0);
2081 __m256d T2 = _mm256_shuffle_pd(kernel.packet[2], kernel.packet[3], 15);
2082 __m256d T3 = _mm256_shuffle_pd(kernel.packet[2], kernel.packet[3], 0);
2083
2084 kernel.packet[1] = _mm256_permute2f128_pd(T0, T2, 32);
2085 kernel.packet[3] = _mm256_permute2f128_pd(T0, T2, 49);
2086 kernel.packet[0] = _mm256_permute2f128_pd(T1, T3, 32);
2087 kernel.packet[2] = _mm256_permute2f128_pd(T1, T3, 49);
2088}
2089
2090// Packet math for Eigen::half
2091#ifndef EIGEN_VECTORIZE_AVX512FP16
2092template <>
2093struct unpacket_traits<Packet8h> {
2094 typedef Eigen::half type;
2095 enum {
2096 size = 8,
2097 alignment = Aligned16,
2098 vectorizable = true,
2099 masked_load_available = false,
2100 masked_store_available = false
2101 };
2102 typedef Packet8h half;
2103};
2104
2105template <>
2106EIGEN_STRONG_INLINE Packet8h pset1<Packet8h>(const Eigen::half& from) {
2107 return _mm_set1_epi16(numext::bit_cast<numext::uint16_t>(from));
2108}
2109
2110template <>
2111EIGEN_STRONG_INLINE Eigen::half pfirst<Packet8h>(const Packet8h& from) {
2112 return numext::bit_cast<Eigen::half>(static_cast<numext::uint16_t>(_mm_extract_epi16(from, 0)));
2113}
2114
2115template <>
2116EIGEN_STRONG_INLINE Packet8h pload<Packet8h>(const Eigen::half* from) {
2117 return _mm_load_si128(reinterpret_cast<const __m128i*>(from));
2118}
2119
2120template <>
2121EIGEN_STRONG_INLINE Packet8h ploadu<Packet8h>(const Eigen::half* from) {
2122 return _mm_loadu_si128(reinterpret_cast<const __m128i*>(from));
2123}
2124
2125template <>
2126EIGEN_STRONG_INLINE void pstore<Eigen::half>(Eigen::half* to, const Packet8h& from) {
2127 _mm_store_si128(reinterpret_cast<__m128i*>(to), from);
2128}
2129
2130template <>
2131EIGEN_STRONG_INLINE void pstoreu<Eigen::half>(Eigen::half* to, const Packet8h& from) {
2132 _mm_storeu_si128(reinterpret_cast<__m128i*>(to), from);
2133}
2134
2135template <>
2136EIGEN_STRONG_INLINE Packet8h ploaddup<Packet8h>(const Eigen::half* from) {
2137 const numext::uint16_t a = numext::bit_cast<numext::uint16_t>(from[0]);
2138 const numext::uint16_t b = numext::bit_cast<numext::uint16_t>(from[1]);
2139 const numext::uint16_t c = numext::bit_cast<numext::uint16_t>(from[2]);
2140 const numext::uint16_t d = numext::bit_cast<numext::uint16_t>(from[3]);
2141 return _mm_set_epi16(d, d, c, c, b, b, a, a);
2142}
2143
2144template <>
2145EIGEN_STRONG_INLINE Packet8h ploadquad<Packet8h>(const Eigen::half* from) {
2146 const numext::uint16_t a = numext::bit_cast<numext::uint16_t>(from[0]);
2147 const numext::uint16_t b = numext::bit_cast<numext::uint16_t>(from[1]);
2148 return _mm_set_epi16(b, b, b, b, a, a, a, a);
2149}
2150
2151template <>
2152EIGEN_STRONG_INLINE Packet8h ptrue(const Packet8h& a) {
2153 return _mm_cmpeq_epi32(a, a);
2154}
2155
2156template <>
2157EIGEN_STRONG_INLINE Packet8h pabs(const Packet8h& a) {
2158 const __m128i sign_mask = _mm_set1_epi16(static_cast<short>(0x8000u));
2159 return _mm_andnot_si128(sign_mask, a);
2160}
2161
2162EIGEN_STRONG_INLINE Packet8f half2float(const Packet8h& a) {
2163#ifdef EIGEN_HAS_FP16_C
2164 return _mm256_cvtph_ps(a);
2165#else
2166 Eigen::internal::Packet8f pp = _mm256_castsi256_ps(
2167 _mm256_insertf128_si256(_mm256_castsi128_si256(half2floatsse(a)), half2floatsse(_mm_srli_si128(a, 8)), 1));
2168 return pp;
2169#endif
2170}
2171
2172EIGEN_STRONG_INLINE Packet8h float2half(const Packet8f& a) {
2173#ifdef EIGEN_HAS_FP16_C
2174 return _mm256_cvtps_ph(a, _MM_FROUND_TO_NEAREST_INT);
2175#else
2176 __m128i lo = float2half(_mm256_extractf128_ps(a, 0));
2177 __m128i hi = float2half(_mm256_extractf128_ps(a, 1));
2178 return _mm_packus_epi32(lo, hi);
2179#endif
2180}
2181
2182template <>
2183EIGEN_STRONG_INLINE Packet8h pmin<Packet8h>(const Packet8h& a, const Packet8h& b) {
2184 return float2half(pmin<Packet8f>(half2float(a), half2float(b)));
2185}
2186
2187template <>
2188EIGEN_STRONG_INLINE Packet8h pmax<Packet8h>(const Packet8h& a, const Packet8h& b) {
2189 return float2half(pmax<Packet8f>(half2float(a), half2float(b)));
2190}
2191
2192template <>
2193EIGEN_STRONG_INLINE Packet8h plset<Packet8h>(const half& a) {
2194 return float2half(plset<Packet8f>(static_cast<float>(a)));
2195}
2196
2197template <>
2198EIGEN_STRONG_INLINE Packet8h por(const Packet8h& a, const Packet8h& b) {
2199 // in some cases Packet4i is a wrapper around __m128i, so we either need to
2200 // cast to Packet4i to directly call the intrinsics as below:
2201 return _mm_or_si128(a, b);
2202}
2203template <>
2204EIGEN_STRONG_INLINE Packet8h pxor(const Packet8h& a, const Packet8h& b) {
2205 return _mm_xor_si128(a, b);
2206}
2207template <>
2208EIGEN_STRONG_INLINE Packet8h pand(const Packet8h& a, const Packet8h& b) {
2209 return _mm_and_si128(a, b);
2210}
2211template <>
2212EIGEN_STRONG_INLINE Packet8h pandnot(const Packet8h& a, const Packet8h& b) {
2213 return _mm_andnot_si128(b, a);
2214}
2215
2216template <>
2217EIGEN_STRONG_INLINE Packet8h pselect(const Packet8h& mask, const Packet8h& a, const Packet8h& b) {
2218 return _mm_blendv_epi8(b, a, mask);
2219}
2220
2221template <>
2222EIGEN_STRONG_INLINE Packet8h pround<Packet8h>(const Packet8h& a) {
2223 return float2half(pround<Packet8f>(half2float(a)));
2224}
2225
2226template <>
2227EIGEN_STRONG_INLINE Packet8h print<Packet8h>(const Packet8h& a) {
2228 return float2half(print<Packet8f>(half2float(a)));
2229}
2230
2231template <>
2232EIGEN_STRONG_INLINE Packet8h pceil<Packet8h>(const Packet8h& a) {
2233 return float2half(pceil<Packet8f>(half2float(a)));
2234}
2235
2236template <>
2237EIGEN_STRONG_INLINE Packet8h pfloor<Packet8h>(const Packet8h& a) {
2238 return float2half(pfloor<Packet8f>(half2float(a)));
2239}
2240
2241template <>
2242EIGEN_STRONG_INLINE Packet8h ptrunc<Packet8h>(const Packet8h& a) {
2243 return float2half(ptrunc<Packet8f>(half2float(a)));
2244}
2245
2246template <>
2247EIGEN_STRONG_INLINE Packet8h pisinf<Packet8h>(const Packet8h& a) {
2248 constexpr uint16_t kInf = ((1 << 5) - 1) << 10;
2249 constexpr uint16_t kAbsMask = (1 << 15) - 1;
2250 return _mm_cmpeq_epi16(_mm_and_si128(a.m_val, _mm_set1_epi16(kAbsMask)), _mm_set1_epi16(kInf));
2251}
2252
2253template <>
2254EIGEN_STRONG_INLINE Packet8h pisnan<Packet8h>(const Packet8h& a) {
2255 constexpr uint16_t kInf = ((1 << 5) - 1) << 10;
2256 constexpr uint16_t kAbsMask = (1 << 15) - 1;
2257 return _mm_cmpgt_epi16(_mm_and_si128(a.m_val, _mm_set1_epi16(kAbsMask)), _mm_set1_epi16(kInf));
2258}
2259
2260// convert the sign-magnitude representation to two's complement
2261EIGEN_STRONG_INLINE __m128i pmaptosigned(const __m128i& a) {
2262 constexpr uint16_t kAbsMask = (1 << 15) - 1;
2263 // if 'a' has the sign bit set, clear the sign bit and negate the result as if it were an integer
2264 return _mm_sign_epi16(_mm_and_si128(a, _mm_set1_epi16(kAbsMask)), a);
2265}
2266
2267// return true if both `a` and `b` are not NaN
2268EIGEN_STRONG_INLINE Packet8h pisordered(const Packet8h& a, const Packet8h& b) {
2269 constexpr uint16_t kInf = ((1 << 5) - 1) << 10;
2270 constexpr uint16_t kAbsMask = (1 << 15) - 1;
2271 __m128i abs_a = _mm_and_si128(a.m_val, _mm_set1_epi16(kAbsMask));
2272 __m128i abs_b = _mm_and_si128(b.m_val, _mm_set1_epi16(kAbsMask));
2273 // check if both `abs_a <= kInf` and `abs_b <= kInf` by checking if max(abs_a, abs_b) <= kInf
2274 // SSE has no `lesser or equal` instruction for integers, but comparing against kInf + 1 accomplishes the same goal
2275 return _mm_cmplt_epi16(_mm_max_epu16(abs_a, abs_b), _mm_set1_epi16(kInf + 1));
2276}
2277
2278template <>
2279EIGEN_STRONG_INLINE Packet8h pcmp_eq(const Packet8h& a, const Packet8h& b) {
2280 __m128i isOrdered = pisordered(a, b);
2281 __m128i isEqual = _mm_cmpeq_epi16(pmaptosigned(a.m_val), pmaptosigned(b.m_val));
2282 return _mm_and_si128(isOrdered, isEqual);
2283}
2284
2285template <>
2286EIGEN_STRONG_INLINE Packet8h pcmp_le(const Packet8h& a, const Packet8h& b) {
2287 __m128i isOrdered = pisordered(a, b);
2288 __m128i isGreater = _mm_cmpgt_epi16(pmaptosigned(a.m_val), pmaptosigned(b.m_val));
2289 return _mm_andnot_si128(isGreater, isOrdered);
2290}
2291
2292template <>
2293EIGEN_STRONG_INLINE Packet8h pcmp_lt(const Packet8h& a, const Packet8h& b) {
2294 __m128i isOrdered = pisordered(a, b);
2295 __m128i isLess = _mm_cmplt_epi16(pmaptosigned(a.m_val), pmaptosigned(b.m_val));
2296 return _mm_and_si128(isOrdered, isLess);
2297}
2298
2299template <>
2300EIGEN_STRONG_INLINE Packet8h pcmp_lt_or_nan(const Packet8h& a, const Packet8h& b) {
2301 __m128i isUnordered = por(pisnan(a), pisnan(b));
2302 __m128i isLess = _mm_cmplt_epi16(pmaptosigned(a.m_val), pmaptosigned(b.m_val));
2303 return _mm_or_si128(isUnordered, isLess);
2304}
2305
2306template <>
2307EIGEN_STRONG_INLINE Packet8h pnegate(const Packet8h& a) {
2308 Packet8h sign_mask = _mm_set1_epi16(static_cast<short>(0x8000u));
2309 return _mm_xor_si128(a, sign_mask);
2310}
2311
2312#ifndef EIGEN_VECTORIZE_AVX512FP16
2313template <>
2314EIGEN_STRONG_INLINE Packet8h padd<Packet8h>(const Packet8h& a, const Packet8h& b) {
2315 Packet8f af = half2float(a);
2316 Packet8f bf = half2float(b);
2317 Packet8f rf = padd(af, bf);
2318 return float2half(rf);
2319}
2320
2321template <>
2322EIGEN_STRONG_INLINE Packet8h psub<Packet8h>(const Packet8h& a, const Packet8h& b) {
2323 Packet8f af = half2float(a);
2324 Packet8f bf = half2float(b);
2325 Packet8f rf = psub(af, bf);
2326 return float2half(rf);
2327}
2328
2329template <>
2330EIGEN_STRONG_INLINE Packet8h pmul<Packet8h>(const Packet8h& a, const Packet8h& b) {
2331 Packet8f af = half2float(a);
2332 Packet8f bf = half2float(b);
2333 Packet8f rf = pmul(af, bf);
2334 return float2half(rf);
2335}
2336
2337template <>
2338EIGEN_STRONG_INLINE Packet8h pmadd<Packet8h>(const Packet8h& a, const Packet8h& b, const Packet8h& c) {
2339 return float2half(pmadd(half2float(a), half2float(b), half2float(c)));
2340}
2341
2342template <>
2343EIGEN_STRONG_INLINE Packet8h pmsub<Packet8h>(const Packet8h& a, const Packet8h& b, const Packet8h& c) {
2344 return float2half(pmsub(half2float(a), half2float(b), half2float(c)));
2345}
2346
2347template <>
2348EIGEN_STRONG_INLINE Packet8h pnmadd<Packet8h>(const Packet8h& a, const Packet8h& b, const Packet8h& c) {
2349 return float2half(pnmadd(half2float(a), half2float(b), half2float(c)));
2350}
2351
2352template <>
2353EIGEN_STRONG_INLINE Packet8h pnmsub<Packet8h>(const Packet8h& a, const Packet8h& b, const Packet8h& c) {
2354 return float2half(pnmsub(half2float(a), half2float(b), half2float(c)));
2355}
2356
2357template <>
2358EIGEN_STRONG_INLINE Packet8h pdiv<Packet8h>(const Packet8h& a, const Packet8h& b) {
2359 Packet8f af = half2float(a);
2360 Packet8f bf = half2float(b);
2361 Packet8f rf = pdiv(af, bf);
2362 return float2half(rf);
2363}
2364#endif
2365
2366template <>
2367EIGEN_STRONG_INLINE Packet8h pgather<Eigen::half, Packet8h>(const Eigen::half* from, Index stride) {
2368 const numext::uint16_t s0 = numext::bit_cast<numext::uint16_t>(from[0 * stride]);
2369 const numext::uint16_t s1 = numext::bit_cast<numext::uint16_t>(from[1 * stride]);
2370 const numext::uint16_t s2 = numext::bit_cast<numext::uint16_t>(from[2 * stride]);
2371 const numext::uint16_t s3 = numext::bit_cast<numext::uint16_t>(from[3 * stride]);
2372 const numext::uint16_t s4 = numext::bit_cast<numext::uint16_t>(from[4 * stride]);
2373 const numext::uint16_t s5 = numext::bit_cast<numext::uint16_t>(from[5 * stride]);
2374 const numext::uint16_t s6 = numext::bit_cast<numext::uint16_t>(from[6 * stride]);
2375 const numext::uint16_t s7 = numext::bit_cast<numext::uint16_t>(from[7 * stride]);
2376 return _mm_set_epi16(s7, s6, s5, s4, s3, s2, s1, s0);
2377}
2378
2379template <>
2380EIGEN_STRONG_INLINE void pscatter<Eigen::half, Packet8h>(Eigen::half* to, const Packet8h& from, Index stride) {
2381 EIGEN_ALIGN32 Eigen::half aux[8];
2382 pstore(aux, from);
2383 to[stride * 0] = aux[0];
2384 to[stride * 1] = aux[1];
2385 to[stride * 2] = aux[2];
2386 to[stride * 3] = aux[3];
2387 to[stride * 4] = aux[4];
2388 to[stride * 5] = aux[5];
2389 to[stride * 6] = aux[6];
2390 to[stride * 7] = aux[7];
2391}
2392
2393template <>
2394EIGEN_STRONG_INLINE Packet8h preverse(const Packet8h& a) {
2395 __m128i m = _mm_setr_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);
2396 return _mm_shuffle_epi8(a, m);
2397}
2398
2399EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet8h, 8>& kernel) {
2400 __m128i a = kernel.packet[0];
2401 __m128i b = kernel.packet[1];
2402 __m128i c = kernel.packet[2];
2403 __m128i d = kernel.packet[3];
2404 __m128i e = kernel.packet[4];
2405 __m128i f = kernel.packet[5];
2406 __m128i g = kernel.packet[6];
2407 __m128i h = kernel.packet[7];
2408
2409 __m128i a03b03 = _mm_unpacklo_epi16(a, b);
2410 __m128i c03d03 = _mm_unpacklo_epi16(c, d);
2411 __m128i e03f03 = _mm_unpacklo_epi16(e, f);
2412 __m128i g03h03 = _mm_unpacklo_epi16(g, h);
2413 __m128i a47b47 = _mm_unpackhi_epi16(a, b);
2414 __m128i c47d47 = _mm_unpackhi_epi16(c, d);
2415 __m128i e47f47 = _mm_unpackhi_epi16(e, f);
2416 __m128i g47h47 = _mm_unpackhi_epi16(g, h);
2417
2418 __m128i a01b01c01d01 = _mm_unpacklo_epi32(a03b03, c03d03);
2419 __m128i a23b23c23d23 = _mm_unpackhi_epi32(a03b03, c03d03);
2420 __m128i e01f01g01h01 = _mm_unpacklo_epi32(e03f03, g03h03);
2421 __m128i e23f23g23h23 = _mm_unpackhi_epi32(e03f03, g03h03);
2422 __m128i a45b45c45d45 = _mm_unpacklo_epi32(a47b47, c47d47);
2423 __m128i a67b67c67d67 = _mm_unpackhi_epi32(a47b47, c47d47);
2424 __m128i e45f45g45h45 = _mm_unpacklo_epi32(e47f47, g47h47);
2425 __m128i e67f67g67h67 = _mm_unpackhi_epi32(e47f47, g47h47);
2426
2427 __m128i a0b0c0d0e0f0g0h0 = _mm_unpacklo_epi64(a01b01c01d01, e01f01g01h01);
2428 __m128i a1b1c1d1e1f1g1h1 = _mm_unpackhi_epi64(a01b01c01d01, e01f01g01h01);
2429 __m128i a2b2c2d2e2f2g2h2 = _mm_unpacklo_epi64(a23b23c23d23, e23f23g23h23);
2430 __m128i a3b3c3d3e3f3g3h3 = _mm_unpackhi_epi64(a23b23c23d23, e23f23g23h23);
2431 __m128i a4b4c4d4e4f4g4h4 = _mm_unpacklo_epi64(a45b45c45d45, e45f45g45h45);
2432 __m128i a5b5c5d5e5f5g5h5 = _mm_unpackhi_epi64(a45b45c45d45, e45f45g45h45);
2433 __m128i a6b6c6d6e6f6g6h6 = _mm_unpacklo_epi64(a67b67c67d67, e67f67g67h67);
2434 __m128i a7b7c7d7e7f7g7h7 = _mm_unpackhi_epi64(a67b67c67d67, e67f67g67h67);
2435
2436 kernel.packet[0] = a0b0c0d0e0f0g0h0;
2437 kernel.packet[1] = a1b1c1d1e1f1g1h1;
2438 kernel.packet[2] = a2b2c2d2e2f2g2h2;
2439 kernel.packet[3] = a3b3c3d3e3f3g3h3;
2440 kernel.packet[4] = a4b4c4d4e4f4g4h4;
2441 kernel.packet[5] = a5b5c5d5e5f5g5h5;
2442 kernel.packet[6] = a6b6c6d6e6f6g6h6;
2443 kernel.packet[7] = a7b7c7d7e7f7g7h7;
2444}
2445
2446EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet8h, 4>& kernel) {
2447 EIGEN_ALIGN32 Eigen::half in[4][8];
2448 pstore<Eigen::half>(in[0], kernel.packet[0]);
2449 pstore<Eigen::half>(in[1], kernel.packet[1]);
2450 pstore<Eigen::half>(in[2], kernel.packet[2]);
2451 pstore<Eigen::half>(in[3], kernel.packet[3]);
2452
2453 EIGEN_ALIGN32 Eigen::half out[4][8];
2454
2455 for (int i = 0; i < 4; ++i) {
2456 for (int j = 0; j < 4; ++j) {
2457 out[i][j] = in[j][2 * i];
2458 }
2459 for (int j = 0; j < 4; ++j) {
2460 out[i][j + 4] = in[j][2 * i + 1];
2461 }
2462 }
2463
2464 kernel.packet[0] = pload<Packet8h>(out[0]);
2465 kernel.packet[1] = pload<Packet8h>(out[1]);
2466 kernel.packet[2] = pload<Packet8h>(out[2]);
2467 kernel.packet[3] = pload<Packet8h>(out[3]);
2468}
2469
2470#endif
2471
2472// BFloat16 implementation.
2473
2474EIGEN_STRONG_INLINE Packet8f Bf16ToF32(const Packet8bf& a) {
2475#ifdef EIGEN_VECTORIZE_AVX2
2476 __m256i extend = _mm256_cvtepu16_epi32(a);
2477 return _mm256_castsi256_ps(_mm256_slli_epi32(extend, 16));
2478#else
2479 __m128i lo = _mm_cvtepu16_epi32(a);
2480 __m128i hi = _mm_cvtepu16_epi32(_mm_srli_si128(a, 8));
2481 __m128i lo_shift = _mm_slli_epi32(lo, 16);
2482 __m128i hi_shift = _mm_slli_epi32(hi, 16);
2483 return _mm256_castsi256_ps(_mm256_insertf128_si256(_mm256_castsi128_si256(lo_shift), hi_shift, 1));
2484#endif
2485}
2486
2487// Convert float to bfloat16 according to round-to-nearest-even/denormals algorithm.
2488EIGEN_STRONG_INLINE Packet8bf F32ToBf16(const Packet8f& a) {
2489 __m256i input = _mm256_castps_si256(a);
2490
2491#ifdef EIGEN_VECTORIZE_AVX2
2492 // uint32_t lsb = (input >> 16);
2493 __m256i t = _mm256_srli_epi32(input, 16);
2494 // uint32_t lsb = lsb & 1;
2495 t = _mm256_and_si256(t, _mm256_set1_epi32(1));
2496 // uint32_t rounding_bias = 0x7fff + lsb;
2497 t = _mm256_add_epi32(t, _mm256_set1_epi32(0x7fff));
2498 // input += rounding_bias;
2499 t = _mm256_add_epi32(t, input);
2500 // input = input >> 16;
2501 t = _mm256_srli_epi32(t, 16);
2502 // Check NaN before converting back to bf16
2503 __m256 mask = _mm256_cmp_ps(a, a, _CMP_ORD_Q);
2504 __m256i nan = _mm256_set1_epi32(0x7fc0);
2505 t = _mm256_blendv_epi8(nan, t, _mm256_castps_si256(mask));
2506 // output = numext::bit_cast<uint16_t>(input);
2507 return _mm_packus_epi32(_mm256_extractf128_si256(t, 0), _mm256_extractf128_si256(t, 1));
2508#else
2509 // uint32_t lsb = (input >> 16);
2510 __m128i lo = _mm_srli_epi32(_mm256_extractf128_si256(input, 0), 16);
2511 __m128i hi = _mm_srli_epi32(_mm256_extractf128_si256(input, 1), 16);
2512 // uint32_t lsb = lsb & 1;
2513 lo = _mm_and_si128(lo, _mm_set1_epi32(1));
2514 hi = _mm_and_si128(hi, _mm_set1_epi32(1));
2515 // uint32_t rounding_bias = 0x7fff + lsb;
2516 lo = _mm_add_epi32(lo, _mm_set1_epi32(0x7fff));
2517 hi = _mm_add_epi32(hi, _mm_set1_epi32(0x7fff));
2518 // input += rounding_bias;
2519 lo = _mm_add_epi32(lo, _mm256_extractf128_si256(input, 0));
2520 hi = _mm_add_epi32(hi, _mm256_extractf128_si256(input, 1));
2521 // input = input >> 16;
2522 lo = _mm_srli_epi32(lo, 16);
2523 hi = _mm_srli_epi32(hi, 16);
2524 // Check NaN before converting back to bf16
2525 __m256 mask = _mm256_cmp_ps(a, a, _CMP_ORD_Q);
2526 __m128i nan = _mm_set1_epi32(0x7fc0);
2527 lo = _mm_blendv_epi8(nan, lo, _mm_castps_si128(_mm256_castps256_ps128(mask)));
2528 hi = _mm_blendv_epi8(nan, hi, _mm_castps_si128(_mm256_extractf128_ps(mask, 1)));
2529 // output = numext::bit_cast<uint16_t>(input);
2530 return _mm_packus_epi32(lo, hi);
2531#endif
2532}
2533
2534template <>
2535EIGEN_STRONG_INLINE Packet8bf pset1<Packet8bf>(const bfloat16& from) {
2536 return _mm_set1_epi16(numext::bit_cast<numext::uint16_t>(from));
2537}
2538
2539template <>
2540EIGEN_STRONG_INLINE bfloat16 pfirst<Packet8bf>(const Packet8bf& from) {
2541 return numext::bit_cast<bfloat16>(static_cast<numext::uint16_t>(_mm_extract_epi16(from, 0)));
2542}
2543
2544template <>
2545EIGEN_STRONG_INLINE Packet8bf pload<Packet8bf>(const bfloat16* from) {
2546 return _mm_load_si128(reinterpret_cast<const __m128i*>(from));
2547}
2548
2549template <>
2550EIGEN_STRONG_INLINE Packet8bf ploadu<Packet8bf>(const bfloat16* from) {
2551 return _mm_loadu_si128(reinterpret_cast<const __m128i*>(from));
2552}
2553
2554template <>
2555EIGEN_STRONG_INLINE void pstore<bfloat16>(bfloat16* to, const Packet8bf& from) {
2556 _mm_store_si128(reinterpret_cast<__m128i*>(to), from);
2557}
2558
2559template <>
2560EIGEN_STRONG_INLINE void pstoreu<bfloat16>(bfloat16* to, const Packet8bf& from) {
2561 _mm_storeu_si128(reinterpret_cast<__m128i*>(to), from);
2562}
2563
2564template <>
2565EIGEN_STRONG_INLINE Packet8bf ploaddup<Packet8bf>(const bfloat16* from) {
2566 const numext::uint16_t a = numext::bit_cast<numext::uint16_t>(from[0]);
2567 const numext::uint16_t b = numext::bit_cast<numext::uint16_t>(from[1]);
2568 const numext::uint16_t c = numext::bit_cast<numext::uint16_t>(from[2]);
2569 const numext::uint16_t d = numext::bit_cast<numext::uint16_t>(from[3]);
2570 return _mm_set_epi16(d, d, c, c, b, b, a, a);
2571}
2572
2573template <>
2574EIGEN_STRONG_INLINE Packet8bf ploadquad<Packet8bf>(const bfloat16* from) {
2575 const numext::uint16_t a = numext::bit_cast<numext::uint16_t>(from[0]);
2576 const numext::uint16_t b = numext::bit_cast<numext::uint16_t>(from[1]);
2577 return _mm_set_epi16(b, b, b, b, a, a, a, a);
2578}
2579
2580// Discard the low 16 bits of each float. Only valid when every lane already holds an exact
2581// bfloat16 value, in which case this agrees with F32ToBf16 but skips its rounding and NaN
2582// canonicalization. pmin/pmax qualify: they return one of their operands bit for bit.
2583EIGEN_STRONG_INLINE Packet8bf F32ToBf16Truncate(const Packet8f& a) {
2584 __m256i input = _mm256_castps_si256(a);
2585#ifdef EIGEN_VECTORIZE_AVX2
2586 __m256i t = _mm256_srli_epi32(input, 16);
2587 return _mm_packus_epi32(_mm256_extractf128_si256(t, 0), _mm256_extractf128_si256(t, 1));
2588#else
2589 __m128i lo = _mm_srli_epi32(_mm256_extractf128_si256(input, 0), 16);
2590 __m128i hi = _mm_srli_epi32(_mm256_extractf128_si256(input, 1), 16);
2591 return _mm_packus_epi32(lo, hi);
2592#endif
2593}
2594
2595template <>
2596EIGEN_STRONG_INLINE Packet8bf ptrue(const Packet8bf& a) {
2597 return _mm_cmpeq_epi32(a, a);
2598}
2599
2600template <>
2601EIGEN_STRONG_INLINE Packet8bf pabs(const Packet8bf& a) {
2602 const __m128i sign_mask = _mm_set1_epi16(static_cast<short>(0x8000u));
2603 return _mm_andnot_si128(sign_mask, a);
2604}
2605
2606template <>
2607EIGEN_STRONG_INLINE Packet8bf pmin<Packet8bf>(const Packet8bf& a, const Packet8bf& b) {
2608 return F32ToBf16Truncate(pmin<Packet8f>(Bf16ToF32(a), Bf16ToF32(b)));
2609}
2610
2611template <>
2612EIGEN_STRONG_INLINE Packet8bf pmax<Packet8bf>(const Packet8bf& a, const Packet8bf& b) {
2613 return F32ToBf16Truncate(pmax<Packet8f>(Bf16ToF32(a), Bf16ToF32(b)));
2614}
2615
2616template <>
2617EIGEN_STRONG_INLINE Packet8bf plset<Packet8bf>(const bfloat16& a) {
2618 return F32ToBf16(plset<Packet8f>(static_cast<float>(a)));
2619}
2620
2621template <>
2622EIGEN_STRONG_INLINE Packet8bf por(const Packet8bf& a, const Packet8bf& b) {
2623 return _mm_or_si128(a, b);
2624}
2625template <>
2626EIGEN_STRONG_INLINE Packet8bf pxor(const Packet8bf& a, const Packet8bf& b) {
2627 return _mm_xor_si128(a, b);
2628}
2629template <>
2630EIGEN_STRONG_INLINE Packet8bf pand(const Packet8bf& a, const Packet8bf& b) {
2631 return _mm_and_si128(a, b);
2632}
2633template <>
2634EIGEN_STRONG_INLINE Packet8bf pandnot(const Packet8bf& a, const Packet8bf& b) {
2635 return _mm_andnot_si128(b, a);
2636}
2637
2638template <>
2639EIGEN_STRONG_INLINE Packet8bf pselect(const Packet8bf& mask, const Packet8bf& a, const Packet8bf& b) {
2640 return _mm_blendv_epi8(b, a, mask);
2641}
2642
2643template <>
2644EIGEN_STRONG_INLINE Packet8bf pround<Packet8bf>(const Packet8bf& a) {
2645 return F32ToBf16Truncate(pround<Packet8f>(Bf16ToF32(a)));
2646}
2647
2648template <>
2649EIGEN_STRONG_INLINE Packet8bf print<Packet8bf>(const Packet8bf& a) {
2650 return F32ToBf16Truncate(print<Packet8f>(Bf16ToF32(a)));
2651}
2652
2653template <>
2654EIGEN_STRONG_INLINE Packet8bf pceil<Packet8bf>(const Packet8bf& a) {
2655 return F32ToBf16Truncate(pceil<Packet8f>(Bf16ToF32(a)));
2656}
2657
2658template <>
2659EIGEN_STRONG_INLINE Packet8bf pfloor<Packet8bf>(const Packet8bf& a) {
2660 return F32ToBf16Truncate(pfloor<Packet8f>(Bf16ToF32(a)));
2661}
2662
2663template <>
2664EIGEN_STRONG_INLINE Packet8bf ptrunc<Packet8bf>(const Packet8bf& a) {
2665 return F32ToBf16Truncate(ptrunc<Packet8f>(Bf16ToF32(a)));
2666}
2667
2668template <>
2669EIGEN_STRONG_INLINE Packet8bf pcmp_eq(const Packet8bf& a, const Packet8bf& b) {
2670 return Pack16To8(pcmp_eq(Bf16ToF32(a), Bf16ToF32(b)));
2671}
2672
2673template <>
2674EIGEN_STRONG_INLINE Packet8bf pcmp_le(const Packet8bf& a, const Packet8bf& b) {
2675 return Pack16To8(pcmp_le(Bf16ToF32(a), Bf16ToF32(b)));
2676}
2677
2678template <>
2679EIGEN_STRONG_INLINE Packet8bf pcmp_lt(const Packet8bf& a, const Packet8bf& b) {
2680 return Pack16To8(pcmp_lt(Bf16ToF32(a), Bf16ToF32(b)));
2681}
2682
2683template <>
2684EIGEN_STRONG_INLINE Packet8bf pcmp_lt_or_nan(const Packet8bf& a, const Packet8bf& b) {
2685 return Pack16To8(pcmp_lt_or_nan(Bf16ToF32(a), Bf16ToF32(b)));
2686}
2687
2688// Classify on the raw bits, as the scalar isinf/isnan/isfinite do: |a| ==, >, < 0x7f80.
2689template <>
2690EIGEN_STRONG_INLINE Packet8bf pisinf<Packet8bf>(const Packet8bf& a) {
2691 constexpr uint16_t kInf = ((1 << 8) - 1) << 7;
2692 constexpr uint16_t kAbsMask = (1 << 15) - 1;
2693 return _mm_cmpeq_epi16(_mm_and_si128(a, _mm_set1_epi16(kAbsMask)), _mm_set1_epi16(kInf));
2694}
2695
2696template <>
2697EIGEN_STRONG_INLINE Packet8bf pisnan<Packet8bf>(const Packet8bf& a) {
2698 constexpr uint16_t kInf = ((1 << 8) - 1) << 7;
2699 constexpr uint16_t kAbsMask = (1 << 15) - 1;
2700 return _mm_cmpgt_epi16(_mm_and_si128(a, _mm_set1_epi16(kAbsMask)), _mm_set1_epi16(kInf));
2701}
2702
2703// Compare encoded lanes: widening bf16 subnormals to float loses them under DAZ/FZ.
2704template <>
2705EIGEN_STRONG_INLINE Packet8bf psign<Packet8bf>(const Packet8bf& a) {
2706 const __m128i magnitude = _mm_and_si128(a, _mm_set1_epi16(0x7fff));
2707 const __m128i is_nan = _mm_cmpgt_epi16(magnitude, _mm_set1_epi16(0x7f80));
2708 const __m128i keep = _mm_or_si128(is_nan, _mm_set1_epi16(static_cast<short>(0xbf80u)));
2709 return _mm_sign_epi16(_mm_and_si128(_mm_or_si128(a, _mm_set1_epi16(0x3f80)), keep), magnitude);
2710}
2711
2712template <>
2713EIGEN_STRONG_INLINE Packet8bf pisfinite<Packet8bf>(const Packet8bf& a) {
2714 constexpr uint16_t kInf = ((1 << 8) - 1) << 7;
2715 constexpr uint16_t kAbsMask = (1 << 15) - 1;
2716 return _mm_cmplt_epi16(_mm_and_si128(a, _mm_set1_epi16(kAbsMask)), _mm_set1_epi16(kInf));
2717}
2718
2719template <>
2720EIGEN_STRONG_INLINE Packet8bf pnegate(const Packet8bf& a) {
2721 Packet8bf sign_mask = _mm_set1_epi16(static_cast<short>(0x8000u));
2722 return _mm_xor_si128(a, sign_mask);
2723}
2724
2725template <>
2726EIGEN_STRONG_INLINE Packet8bf padd<Packet8bf>(const Packet8bf& a, const Packet8bf& b) {
2727 return F32ToBf16(padd<Packet8f>(Bf16ToF32(a), Bf16ToF32(b)));
2728}
2729
2730template <>
2731EIGEN_STRONG_INLINE Packet8bf psub<Packet8bf>(const Packet8bf& a, const Packet8bf& b) {
2732 return F32ToBf16(psub<Packet8f>(Bf16ToF32(a), Bf16ToF32(b)));
2733}
2734
2735template <>
2736EIGEN_STRONG_INLINE Packet8bf pmul<Packet8bf>(const Packet8bf& a, const Packet8bf& b) {
2737 return F32ToBf16(pmul<Packet8f>(Bf16ToF32(a), Bf16ToF32(b)));
2738}
2739
2740template <>
2741EIGEN_STRONG_INLINE Packet8bf pmadd<Packet8bf>(const Packet8bf& a, const Packet8bf& b, const Packet8bf& c) {
2742 return F32ToBf16(pmadd(Bf16ToF32(a), Bf16ToF32(b), Bf16ToF32(c)));
2743}
2744
2745template <>
2746EIGEN_STRONG_INLINE Packet8bf pmsub<Packet8bf>(const Packet8bf& a, const Packet8bf& b, const Packet8bf& c) {
2747 return F32ToBf16(pmsub(Bf16ToF32(a), Bf16ToF32(b), Bf16ToF32(c)));
2748}
2749
2750template <>
2751EIGEN_STRONG_INLINE Packet8bf pnmadd<Packet8bf>(const Packet8bf& a, const Packet8bf& b, const Packet8bf& c) {
2752 return F32ToBf16(pnmadd(Bf16ToF32(a), Bf16ToF32(b), Bf16ToF32(c)));
2753}
2754
2755template <>
2756EIGEN_STRONG_INLINE Packet8bf pnmsub<Packet8bf>(const Packet8bf& a, const Packet8bf& b, const Packet8bf& c) {
2757 return F32ToBf16(pnmsub(Bf16ToF32(a), Bf16ToF32(b), Bf16ToF32(c)));
2758}
2759
2760template <>
2761EIGEN_STRONG_INLINE Packet8bf pdiv<Packet8bf>(const Packet8bf& a, const Packet8bf& b) {
2762 return F32ToBf16(pdiv<Packet8f>(Bf16ToF32(a), Bf16ToF32(b)));
2763}
2764
2765template <>
2766EIGEN_STRONG_INLINE Packet8bf pgather<bfloat16, Packet8bf>(const bfloat16* from, Index stride) {
2767 const numext::uint16_t s0 = numext::bit_cast<numext::uint16_t>(from[0 * stride]);
2768 const numext::uint16_t s1 = numext::bit_cast<numext::uint16_t>(from[1 * stride]);
2769 const numext::uint16_t s2 = numext::bit_cast<numext::uint16_t>(from[2 * stride]);
2770 const numext::uint16_t s3 = numext::bit_cast<numext::uint16_t>(from[3 * stride]);
2771 const numext::uint16_t s4 = numext::bit_cast<numext::uint16_t>(from[4 * stride]);
2772 const numext::uint16_t s5 = numext::bit_cast<numext::uint16_t>(from[5 * stride]);
2773 const numext::uint16_t s6 = numext::bit_cast<numext::uint16_t>(from[6 * stride]);
2774 const numext::uint16_t s7 = numext::bit_cast<numext::uint16_t>(from[7 * stride]);
2775 return _mm_set_epi16(s7, s6, s5, s4, s3, s2, s1, s0);
2776}
2777
2778template <>
2779EIGEN_STRONG_INLINE void pscatter<bfloat16, Packet8bf>(bfloat16* to, const Packet8bf& from, Index stride) {
2780 EIGEN_ALIGN32 bfloat16 aux[8];
2781 pstore(aux, from);
2782 to[stride * 0] = aux[0];
2783 to[stride * 1] = aux[1];
2784 to[stride * 2] = aux[2];
2785 to[stride * 3] = aux[3];
2786 to[stride * 4] = aux[4];
2787 to[stride * 5] = aux[5];
2788 to[stride * 6] = aux[6];
2789 to[stride * 7] = aux[7];
2790}
2791
2792template <>
2793EIGEN_STRONG_INLINE Packet8bf preverse(const Packet8bf& a) {
2794 __m128i m = _mm_setr_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);
2795 return _mm_shuffle_epi8(a, m);
2796}
2797
2798EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet8bf, 8>& kernel) {
2799 __m128i a = kernel.packet[0];
2800 __m128i b = kernel.packet[1];
2801 __m128i c = kernel.packet[2];
2802 __m128i d = kernel.packet[3];
2803 __m128i e = kernel.packet[4];
2804 __m128i f = kernel.packet[5];
2805 __m128i g = kernel.packet[6];
2806 __m128i h = kernel.packet[7];
2807
2808 __m128i a03b03 = _mm_unpacklo_epi16(a, b);
2809 __m128i c03d03 = _mm_unpacklo_epi16(c, d);
2810 __m128i e03f03 = _mm_unpacklo_epi16(e, f);
2811 __m128i g03h03 = _mm_unpacklo_epi16(g, h);
2812 __m128i a47b47 = _mm_unpackhi_epi16(a, b);
2813 __m128i c47d47 = _mm_unpackhi_epi16(c, d);
2814 __m128i e47f47 = _mm_unpackhi_epi16(e, f);
2815 __m128i g47h47 = _mm_unpackhi_epi16(g, h);
2816
2817 __m128i a01b01c01d01 = _mm_unpacklo_epi32(a03b03, c03d03);
2818 __m128i a23b23c23d23 = _mm_unpackhi_epi32(a03b03, c03d03);
2819 __m128i e01f01g01h01 = _mm_unpacklo_epi32(e03f03, g03h03);
2820 __m128i e23f23g23h23 = _mm_unpackhi_epi32(e03f03, g03h03);
2821 __m128i a45b45c45d45 = _mm_unpacklo_epi32(a47b47, c47d47);
2822 __m128i a67b67c67d67 = _mm_unpackhi_epi32(a47b47, c47d47);
2823 __m128i e45f45g45h45 = _mm_unpacklo_epi32(e47f47, g47h47);
2824 __m128i e67f67g67h67 = _mm_unpackhi_epi32(e47f47, g47h47);
2825
2826 kernel.packet[0] = _mm_unpacklo_epi64(a01b01c01d01, e01f01g01h01);
2827 kernel.packet[1] = _mm_unpackhi_epi64(a01b01c01d01, e01f01g01h01);
2828 kernel.packet[2] = _mm_unpacklo_epi64(a23b23c23d23, e23f23g23h23);
2829 kernel.packet[3] = _mm_unpackhi_epi64(a23b23c23d23, e23f23g23h23);
2830 kernel.packet[4] = _mm_unpacklo_epi64(a45b45c45d45, e45f45g45h45);
2831 kernel.packet[5] = _mm_unpackhi_epi64(a45b45c45d45, e45f45g45h45);
2832 kernel.packet[6] = _mm_unpacklo_epi64(a67b67c67d67, e67f67g67h67);
2833 kernel.packet[7] = _mm_unpackhi_epi64(a67b67c67d67, e67f67g67h67);
2834}
2835
2836EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet8bf, 4>& kernel) {
2837 __m128i a = kernel.packet[0];
2838 __m128i b = kernel.packet[1];
2839 __m128i c = kernel.packet[2];
2840 __m128i d = kernel.packet[3];
2841
2842 __m128i ab_03 = _mm_unpacklo_epi16(a, b);
2843 __m128i cd_03 = _mm_unpacklo_epi16(c, d);
2844 __m128i ab_47 = _mm_unpackhi_epi16(a, b);
2845 __m128i cd_47 = _mm_unpackhi_epi16(c, d);
2846
2847 kernel.packet[0] = _mm_unpacklo_epi32(ab_03, cd_03);
2848 kernel.packet[1] = _mm_unpackhi_epi32(ab_03, cd_03);
2849 kernel.packet[2] = _mm_unpacklo_epi32(ab_47, cd_47);
2850 kernel.packet[3] = _mm_unpackhi_epi32(ab_47, cd_47);
2851}
2852
2853/*---------------- load/store segment support ----------------*/
2854
2855template <>
2856struct has_packet_segment<Packet4f> : std::true_type {};
2857
2858template <>
2859struct has_packet_segment<Packet8f> : std::true_type {};
2860
2861template <>
2862struct has_packet_segment<Packet4i> : std::true_type {};
2863
2864template <>
2865struct has_packet_segment<Packet8i> : std::true_type {};
2866
2867template <>
2868struct has_packet_segment<Packet4ui> : std::true_type {};
2869
2870template <>
2871struct has_packet_segment<Packet8ui> : std::true_type {};
2872
2873template <>
2874struct has_packet_segment<Packet2d> : std::true_type {};
2875
2876template <>
2877struct has_packet_segment<Packet4d> : std::true_type {};
2878
2879#ifdef EIGEN_VECTORIZE_AVX2
2880template <>
2881struct has_packet_segment<Packet2l> : std::true_type {};
2882
2883template <>
2884struct has_packet_segment<Packet4l> : std::true_type {};
2885
2886template <>
2887struct has_packet_segment<Packet4ul> : std::true_type {};
2888#endif
2889
2890// With AVX-512VL these packets use k-masked loads and stores instead; see AVX512/PacketMath.h.
2891#ifndef EIGEN_VECTORIZE_AVX512VL
2892
2893// returns a mask of 8-bit elements (at most 4) that are all 1's in the range [begin, begin + count) and 0 elsewhere.
2894inline __m128i segment_mask_4x8(Index begin, Index count) {
2895 eigen_assert(begin >= 0 && begin + count <= 4);
2896 long long mask = 1;
2897 mask <<= CHAR_BIT * count;
2898 mask--;
2899 mask <<= CHAR_BIT * begin;
2900#if !EIGEN_ARCH_x86_64
2901 return _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&mask));
2902#else
2903 return _mm_cvtsi64_si128(mask);
2904#endif
2905}
2906
2907// returns a mask of 8-bit elements (at most 8) that are all 1's in the range [begin, begin + count) and 0 elsewhere.
2908inline __m128i segment_mask_8x8(Index begin, Index count) {
2909 eigen_assert(begin >= 0 && begin + count <= 8);
2910 long long mask = 1;
2911 // avoid UB when count == 8
2912 mask <<= (CHAR_BIT / 2) * count;
2913 mask <<= (CHAR_BIT / 2) * count;
2914 mask--;
2915 mask <<= CHAR_BIT * begin;
2916#if !EIGEN_ARCH_x86_64
2917 return _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&mask));
2918#else
2919 return _mm_cvtsi64_si128(mask);
2920#endif
2921}
2922
2923// returns a mask of 32-bit elements (at most 4) that are all 1's in the range [begin, begin + count) and 0 elsewhere.
2924inline __m128i segment_mask_4x32(Index begin, Index count) {
2925 eigen_assert(begin >= 0 && begin + count <= 4);
2926 return _mm_cvtepi8_epi32(segment_mask_4x8(begin, count));
2927}
2928
2929// returns a mask of 64-bit elements (at most 2) that are all 1's in the range [begin, begin + count) and 0 elsewhere.
2930inline __m128i segment_mask_2x64(Index begin, Index count) {
2931 eigen_assert(begin >= 0 && begin + count <= 2);
2932 return _mm_cvtepi8_epi64(segment_mask_4x8(begin, count));
2933}
2934
2935// returns a mask of 32-bit elements (at most 8) that are all 1's in the range [begin, begin + count) and 0 elsewhere.
2936inline __m256i segment_mask_8x32(Index begin, Index count) {
2937 __m128i mask_epi8 = segment_mask_8x8(begin, count);
2938#ifdef EIGEN_VECTORIZE_AVX2
2939 __m256i mask_epi32 = _mm256_cvtepi8_epi32(mask_epi8);
2940#else
2941 __m128i mask_epi32_lo = _mm_cvtepi8_epi32(mask_epi8);
2942 __m128i mask_epi32_hi = _mm_cvtepi8_epi32(_mm_srli_epi64(mask_epi8, 32));
2943 __m256i mask_epi32 = _mm256_insertf128_si256(_mm256_castsi128_si256(mask_epi32_lo), mask_epi32_hi, 1);
2944#endif
2945 return mask_epi32;
2946}
2947
2948// returns a mask of 64-bit elements (at most 4) that are all 1's in the range [begin, begin + count) and 0 elsewhere.
2949inline __m256i segment_mask_4x64(Index begin, Index count) {
2950 __m128i mask_epi8 = segment_mask_4x8(begin, count);
2951#ifdef EIGEN_VECTORIZE_AVX2
2952 __m256i mask_epi64 = _mm256_cvtepi8_epi64(mask_epi8);
2953#else
2954 __m128i mask_epi64_lo = _mm_cvtepi8_epi64(mask_epi8);
2955 __m128i mask_epi64_hi = _mm_cvtepi8_epi64(_mm_srli_epi64(mask_epi8, 16));
2956 __m256i mask_epi64 = _mm256_insertf128_si256(_mm256_castsi128_si256(mask_epi64_lo), mask_epi64_hi, 1);
2957#endif
2958 return mask_epi64;
2959}
2960
2961/*---------------- float ----------------*/
2962
2963template <>
2964inline Packet4f ploaduSegment<Packet4f>(const float* from, Index begin, Index count) {
2965 return _mm_maskload_ps(from, segment_mask_4x32(begin, count));
2966}
2967
2968template <>
2969inline void pstoreuSegment<float, Packet4f>(float* to, const Packet4f& from, Index begin, Index count) {
2970 _mm_maskstore_ps(to, segment_mask_4x32(begin, count), from);
2971}
2972
2973template <>
2974inline Packet8f ploaduSegment<Packet8f>(const float* from, Index begin, Index count) {
2975 return _mm256_maskload_ps(from, segment_mask_8x32(begin, count));
2976}
2977
2978template <>
2979inline void pstoreuSegment<float, Packet8f>(float* to, const Packet8f& from, Index begin, Index count) {
2980 _mm256_maskstore_ps(to, segment_mask_8x32(begin, count), from);
2981}
2982
2983/*---------------- int32 ----------------*/
2984
2985#ifdef EIGEN_VECTORIZE_AVX2
2986
2987template <>
2988inline Packet4i ploaduSegment<Packet4i>(const int* from, Index begin, Index count) {
2989 return _mm_maskload_epi32(from, segment_mask_4x32(begin, count));
2990}
2991
2992template <>
2993inline void pstoreuSegment<int, Packet4i>(int* to, const Packet4i& from, Index begin, Index count) {
2994 _mm_maskstore_epi32(to, segment_mask_4x32(begin, count), from);
2995}
2996
2997template <>
2998inline Packet8i ploaduSegment<Packet8i>(const int* from, Index begin, Index count) {
2999 return _mm256_maskload_epi32(from, segment_mask_8x32(begin, count));
3000}
3001
3002template <>
3003inline void pstoreuSegment<int, Packet8i>(int* to, const Packet8i& from, Index begin, Index count) {
3004 _mm256_maskstore_epi32(to, segment_mask_8x32(begin, count), from);
3005}
3006
3007#else
3008
3009template <>
3010inline Packet4i ploaduSegment<Packet4i>(const int* from, Index begin, Index count) {
3011 return _mm_castps_si128(ploaduSegment<Packet4f>(reinterpret_cast<const float*>(from), begin, count));
3012}
3013
3014template <>
3015inline void pstoreuSegment<int, Packet4i>(int* to, const Packet4i& from, Index begin, Index count) {
3016 pstoreuSegment<float, Packet4f>(reinterpret_cast<float*>(to), _mm_castsi128_ps(from), begin, count);
3017}
3018
3019template <>
3020inline Packet8i ploaduSegment<Packet8i>(const int* from, Index begin, Index count) {
3021 return _mm256_castps_si256(ploaduSegment<Packet8f>(reinterpret_cast<const float*>(from), begin, count));
3022}
3023
3024template <>
3025inline void pstoreuSegment<int, Packet8i>(int* to, const Packet8i& from, Index begin, Index count) {
3026 pstoreuSegment<float, Packet8f>(reinterpret_cast<float*>(to), _mm256_castsi256_ps(from), begin, count);
3027}
3028
3029#endif
3030
3031/*---------------- uint32 ----------------*/
3032
3033template <>
3034inline Packet4ui ploaduSegment<Packet4ui>(const uint32_t* from, Index begin, Index count) {
3035 return Packet4ui(ploaduSegment<Packet4i>(reinterpret_cast<const int*>(from), begin, count));
3036}
3037
3038template <>
3039inline void pstoreuSegment<uint32_t, Packet4ui>(uint32_t* to, const Packet4ui& from, Index begin, Index count) {
3040 pstoreuSegment<int, Packet4i>(reinterpret_cast<int*>(to), Packet4i(from), begin, count);
3041}
3042
3043template <>
3044inline Packet8ui ploaduSegment<Packet8ui>(const uint32_t* from, Index begin, Index count) {
3045 return Packet8ui(ploaduSegment<Packet8i>(reinterpret_cast<const int*>(from), begin, count));
3046}
3047
3048template <>
3049inline void pstoreuSegment<uint32_t, Packet8ui>(uint32_t* to, const Packet8ui& from, Index begin, Index count) {
3050 pstoreuSegment<int, Packet8i>(reinterpret_cast<int*>(to), Packet8i(from), begin, count);
3051}
3052
3053/*---------------- double ----------------*/
3054
3055template <>
3056inline Packet2d ploaduSegment<Packet2d>(const double* from, Index begin, Index count) {
3057 return _mm_maskload_pd(from, segment_mask_2x64(begin, count));
3058}
3059
3060template <>
3061inline void pstoreuSegment<double, Packet2d>(double* to, const Packet2d& from, Index begin, Index count) {
3062 _mm_maskstore_pd(to, segment_mask_2x64(begin, count), from);
3063}
3064
3065template <>
3066inline Packet4d ploaduSegment<Packet4d>(const double* from, Index begin, Index count) {
3067 return _mm256_maskload_pd(from, segment_mask_4x64(begin, count));
3068}
3069
3070template <>
3071inline void pstoreuSegment<double, Packet4d>(double* to, const Packet4d& from, Index begin, Index count) {
3072 _mm256_maskstore_pd(to, segment_mask_4x64(begin, count), from);
3073}
3074
3075#ifdef EIGEN_VECTORIZE_AVX2
3076
3077/*---------------- int64_t ----------------*/
3078
3079template <>
3080inline Packet2l ploaduSegment<Packet2l>(const int64_t* from, Index begin, Index count) {
3081 return _mm_maskload_epi64(reinterpret_cast<const long long*>(from), segment_mask_2x64(begin, count));
3082}
3083template <>
3084inline void pstoreuSegment<int64_t, Packet2l>(int64_t* to, const Packet2l& from, Index begin, Index count) {
3085 _mm_maskstore_epi64(reinterpret_cast<long long*>(to), segment_mask_2x64(begin, count), from);
3086}
3087template <>
3088inline Packet4l ploaduSegment<Packet4l>(const int64_t* from, Index begin, Index count) {
3089 return _mm256_maskload_epi64(reinterpret_cast<const long long*>(from), segment_mask_4x64(begin, count));
3090}
3091template <>
3092inline void pstoreuSegment<int64_t, Packet4l>(int64_t* to, const Packet4l& from, Index begin, Index count) {
3093 _mm256_maskstore_epi64(reinterpret_cast<long long*>(to), segment_mask_4x64(begin, count), from);
3094}
3095
3096/*---------------- uint64_t ----------------*/
3097
3098template <>
3099inline Packet4ul ploaduSegment<Packet4ul>(const uint64_t* from, Index begin, Index count) {
3100 return Packet4ul(ploaduSegment<Packet4l>(reinterpret_cast<const int64_t*>(from), begin, count));
3101}
3102template <>
3103inline void pstoreuSegment<uint64_t, Packet4ul>(uint64_t* to, const Packet4ul& from, Index begin, Index count) {
3104 pstoreuSegment<int64_t, Packet4l>(reinterpret_cast<int64_t*>(to), Packet4l(from), begin, count);
3105}
3106#endif
3107
3108#endif // EIGEN_VECTORIZE_AVX512VL
3109
3110/*---------------- end load/store segment support ----------------*/
3111
3112} // end namespace internal
3113
3114} // end namespace Eigen
3115
3116#endif // EIGEN_PACKET_MATH_AVX_H
@ Aligned32
Definition Constants.h:239
@ Aligned16
Definition Constants.h:238