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) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
5// Copyright (C) 2010 Konstantinos Margaritis <markos@freevec.org>
6// Heavily based on Gael's SSE version.
7//
8// This Source Code Form is subject to the terms of the Mozilla
9// Public License v. 2.0. If a copy of the MPL was not distributed
10// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
11// SPDX-License-Identifier: MPL-2.0
12
13#ifndef EIGEN_PACKET_MATH_NEON_H
14#define EIGEN_PACKET_MATH_NEON_H
15
16// IWYU pragma: private
17#include "../../InternalHeaderCheck.h"
18
19namespace Eigen {
20
21namespace internal {
22
23#ifndef EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD
24#define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 8
25#endif
26
27#ifndef EIGEN_HAS_SINGLE_INSTRUCTION_MADD
28#define EIGEN_HAS_SINGLE_INSTRUCTION_MADD
29#endif
30
31#ifndef EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS
32#if EIGEN_ARCH_ARM64
33#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 32
34#else
35#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 16
36#endif
37#endif
38
39#if EIGEN_COMP_MSVC_STRICT
40
41// In MSVC's arm_neon.h header file, all NEON vector types
42// are aliases to the same underlying type __n128.
43// We thus have to wrap them to make them different C++ types.
44// (See also bug 1428)
45typedef eigen_packet_wrapper<float32x2_t, 0> Packet2f;
46typedef eigen_packet_wrapper<float32x4_t, 1> Packet4f;
47typedef eigen_packet_wrapper<int32_t, 2> Packet4c;
48typedef eigen_packet_wrapper<int8x8_t, 3> Packet8c;
49typedef eigen_packet_wrapper<int8x16_t, 4> Packet16c;
50typedef eigen_packet_wrapper<uint32_t, 5> Packet4uc;
51typedef eigen_packet_wrapper<uint8x8_t, 6> Packet8uc;
52typedef eigen_packet_wrapper<uint8x16_t, 7> Packet16uc;
53typedef eigen_packet_wrapper<int16x4_t, 8> Packet4s;
54typedef eigen_packet_wrapper<int16x8_t, 9> Packet8s;
55typedef eigen_packet_wrapper<uint16x4_t, 10> Packet4us;
56typedef eigen_packet_wrapper<uint16x8_t, 11> Packet8us;
57typedef eigen_packet_wrapper<int32x2_t, 12> Packet2i;
58typedef eigen_packet_wrapper<int32x4_t, 13> Packet4i;
59typedef eigen_packet_wrapper<uint32x2_t, 14> Packet2ui;
60typedef eigen_packet_wrapper<uint32x4_t, 15> Packet4ui;
61typedef eigen_packet_wrapper<int64x2_t, 16> Packet2l;
62typedef eigen_packet_wrapper<uint64x2_t, 17> Packet2ul;
63
64EIGEN_ALWAYS_INLINE Packet4f make_packet4f(float a, float b, float c, float d) {
65 float from[4] = {a, b, c, d};
66 return vld1q_f32(from);
67}
68
69EIGEN_ALWAYS_INLINE Packet2f make_packet2f(float a, float b) {
70 float from[2] = {a, b};
71 return vld1_f32(from);
72}
73
74#else
75
76typedef float32x2_t Packet2f;
77typedef float32x4_t Packet4f;
78typedef eigen_packet_wrapper<int32_t, 2> Packet4c;
79typedef int8x8_t Packet8c;
80typedef int8x16_t Packet16c;
81typedef eigen_packet_wrapper<uint32_t, 5> Packet4uc;
82typedef uint8x8_t Packet8uc;
83typedef uint8x16_t Packet16uc;
84typedef int16x4_t Packet4s;
85typedef int16x8_t Packet8s;
86typedef uint16x4_t Packet4us;
87typedef uint16x8_t Packet8us;
88typedef int32x2_t Packet2i;
89typedef int32x4_t Packet4i;
90typedef uint32x2_t Packet2ui;
91typedef uint32x4_t Packet4ui;
92typedef int64x2_t Packet2l;
93typedef uint64x2_t Packet2ul;
94
95EIGEN_ALWAYS_INLINE Packet4f make_packet4f(float a, float b, float c, float d) { return Packet4f{a, b, c, d}; }
96EIGEN_ALWAYS_INLINE Packet2f make_packet2f(float a, float b) { return Packet2f{a, b}; }
97
98#endif // EIGEN_COMP_MSVC_STRICT
99
100EIGEN_STRONG_INLINE Packet4f shuffle1(const Packet4f& m, int mask) {
101 const float* a = reinterpret_cast<const float*>(&m);
102 Packet4f res =
103 make_packet4f(*(a + (mask & 3)), *(a + ((mask >> 2) & 3)), *(a + ((mask >> 4) & 3)), *(a + ((mask >> 6) & 3)));
104 return res;
105}
106
107// functionally equivalent to _mm_shuffle_ps in SSE when interleave
108// == false (i.e. shuffle<false>(m, n, mask) equals _mm_shuffle_ps(m, n, mask)),
109// interleave m and n when interleave == true. Currently used in LU/arch/InverseSize4.h
110// to enable a shared implementation for fast inversion of matrices of size 4.
111template <bool interleave>
112EIGEN_STRONG_INLINE Packet4f shuffle2(const Packet4f& m, const Packet4f& n, int mask) {
113 const float* a = reinterpret_cast<const float*>(&m);
114 const float* b = reinterpret_cast<const float*>(&n);
115 Packet4f res =
116 make_packet4f(*(a + (mask & 3)), *(a + ((mask >> 2) & 3)), *(b + ((mask >> 4) & 3)), *(b + ((mask >> 6) & 3)));
117 return res;
118}
119
120template <>
121EIGEN_STRONG_INLINE Packet4f shuffle2<true>(const Packet4f& m, const Packet4f& n, int mask) {
122 const float* a = reinterpret_cast<const float*>(&m);
123 const float* b = reinterpret_cast<const float*>(&n);
124 Packet4f res =
125 make_packet4f(*(a + (mask & 3)), *(b + ((mask >> 2) & 3)), *(a + ((mask >> 4) & 3)), *(b + ((mask >> 6) & 3)));
126 return res;
127}
128
129EIGEN_STRONG_INLINE static int eigen_neon_shuffle_mask(int p, int q, int r, int s) {
130 return ((s) << 6 | (r) << 4 | (q) << 2 | (p));
131}
132
133EIGEN_STRONG_INLINE Packet4f vec4f_swizzle1(const Packet4f& a, int p, int q, int r, int s) {
134 return shuffle1(a, eigen_neon_shuffle_mask(p, q, r, s));
135}
136EIGEN_STRONG_INLINE Packet4f vec4f_swizzle2(const Packet4f& a, const Packet4f& b, int p, int q, int r, int s) {
137 return shuffle2<false>(a, b, eigen_neon_shuffle_mask(p, q, r, s));
138}
139EIGEN_STRONG_INLINE Packet4f vec4f_movelh(const Packet4f& a, const Packet4f& b) {
140 return shuffle2<false>(a, b, eigen_neon_shuffle_mask(0, 1, 0, 1));
141}
142EIGEN_STRONG_INLINE Packet4f vec4f_movehl(const Packet4f& a, const Packet4f& b) {
143 return shuffle2<false>(b, a, eigen_neon_shuffle_mask(2, 3, 2, 3));
144}
145EIGEN_STRONG_INLINE Packet4f vec4f_unpacklo(const Packet4f& a, const Packet4f& b) {
146 return shuffle2<true>(a, b, eigen_neon_shuffle_mask(0, 0, 1, 1));
147}
148EIGEN_STRONG_INLINE Packet4f vec4f_unpackhi(const Packet4f& a, const Packet4f& b) {
149 return shuffle2<true>(a, b, eigen_neon_shuffle_mask(2, 2, 3, 3));
150}
151#define vec4f_duplane(a, p) Packet4f(vdupq_lane_f32(vget_low_f32(a), p))
152
153#define EIGEN_DECLARE_CONST_Packet4f(NAME, X) const Packet4f p4f_##NAME = pset1<Packet4f>(X)
154
155#define EIGEN_DECLARE_CONST_Packet4f_FROM_INT(NAME, X) \
156 const Packet4f p4f_##NAME = vreinterpretq_f32_u32(pset1<int32_t>(X))
157
158#define EIGEN_DECLARE_CONST_Packet4i(NAME, X) const Packet4i p4i_##NAME = pset1<Packet4i>(X)
159
160#if EIGEN_ARCH_ARM64 && EIGEN_COMP_GNUC
161// __builtin_prefetch tends to do nothing on ARM64 compilers because the
162// prefetch instructions there are too detailed for __builtin_prefetch to map
163// meaningfully to them.
164#define EIGEN_ARM_PREFETCH(ADDR) __asm__ __volatile__("prfm pldl1keep, [%[addr]]\n" ::[addr] "r"(ADDR) :);
165#elif EIGEN_HAS_BUILTIN(__builtin_prefetch) || EIGEN_COMP_GNUC
166#define EIGEN_ARM_PREFETCH(ADDR) __builtin_prefetch(ADDR);
167#elif defined __pld
168#define EIGEN_ARM_PREFETCH(ADDR) __pld(ADDR)
169#elif EIGEN_ARCH_ARM
170#define EIGEN_ARM_PREFETCH(ADDR) __asm__ __volatile__("pld [%[addr]]\n" ::[addr] "r"(ADDR) :);
171#else
172// by default no explicit prefetching
173#define EIGEN_ARM_PREFETCH(ADDR)
174#endif
175
176template <>
177struct packet_traits<float> : default_packet_traits {
178 typedef Packet4f type;
179 typedef Packet2f half;
180 enum {
181 Vectorizable = 1,
182 AlignedOnScalar = 1,
183 size = 4,
184
185 HasCmp = 1,
186 HasAdd = 1,
187 HasSub = 1,
188 HasShift = 1,
189 HasMul = 1,
190 HasNegate = 1,
191 HasAbs = 1,
192 HasArg = 0,
193 HasAbsDiff = 1,
194 HasMin = 1,
195 HasMax = 1,
196 HasConj = 1,
197 HasSetLinear = 1,
198 HasDiv = 1,
199 HasSin = EIGEN_FAST_MATH,
200 HasCos = EIGEN_FAST_MATH,
201 HasTan = EIGEN_FAST_MATH,
202 HasACos = 1,
203 HasASin = 1,
204 HasATan = 1,
205 HasATanh = 1,
206 HasSinh = 1,
207 HasCosh = 1,
208 HasASinh = 1,
209 HasACosh = 1,
210 HasLog = 1,
211 HasLog10 = 1,
212 HasExp = 1,
213 HasLog1p = 1,
214 HasExpm1 = 1,
215 HasPow = 1,
216 HasSqrt = 1,
217 HasRsqrt = 1,
218 HasCbrt = 1,
219 HasTanh = EIGEN_FAST_MATH,
220 HasErf = EIGEN_FAST_MATH,
221 HasErfc = EIGEN_FAST_MATH,
222 HasBessel = 0, // Issues with accuracy.
223 HasNdtri = 0
224 };
225};
226
227template <>
228struct packet_traits<int8_t> : default_packet_traits {
229 typedef Packet16c type;
230 typedef Packet8c half;
231 enum {
232 Vectorizable = 1,
233 AlignedOnScalar = 1,
234 size = 16,
235
236 HasCmp = 1,
237 HasAdd = 1,
238 HasSub = 1,
239 HasShift = 1,
240 HasMul = 1,
241 HasNegate = 1,
242 HasAbs = 1,
243 HasAbsDiff = 1,
244 HasArg = 0,
245 HasMin = 1,
246 HasMax = 1,
247 HasConj = 1,
248 HasSetLinear = 1,
249 };
250};
251
252template <>
253struct packet_traits<uint8_t> : default_packet_traits {
254 typedef Packet16uc type;
255 typedef Packet8uc half;
256 enum {
257 Vectorizable = 1,
258 AlignedOnScalar = 1,
259 size = 16,
260
261 HasCmp = 1,
262 HasAdd = 1,
263 HasSub = 1,
264 HasShift = 1,
265 HasMul = 1,
266 HasNegate = 0,
267 HasAbs = 1,
268 HasAbsDiff = 1,
269 HasArg = 0,
270 HasMin = 1,
271 HasMax = 1,
272 HasConj = 1,
273 HasSetLinear = 1,
274
275 HasSqrt = 1
276 };
277};
278
279template <>
280struct packet_traits<int16_t> : default_packet_traits {
281 typedef Packet8s type;
282 typedef Packet4s half;
283 enum {
284 Vectorizable = 1,
285 AlignedOnScalar = 1,
286 size = 8,
287
288 HasCmp = 1,
289 HasAdd = 1,
290 HasSub = 1,
291 HasShift = 1,
292 HasMul = 1,
293 HasNegate = 1,
294 HasAbs = 1,
295 HasAbsDiff = 1,
296 HasArg = 0,
297 HasMin = 1,
298 HasMax = 1,
299 HasConj = 1,
300 HasSetLinear = 1,
301 };
302};
303
304template <>
305struct packet_traits<uint16_t> : default_packet_traits {
306 typedef Packet8us type;
307 typedef Packet4us half;
308 enum {
309 Vectorizable = 1,
310 AlignedOnScalar = 1,
311 size = 8,
312
313 HasCmp = 1,
314 HasAdd = 1,
315 HasSub = 1,
316 HasShift = 1,
317 HasMul = 1,
318 HasNegate = 0,
319 HasAbs = 1,
320 HasAbsDiff = 1,
321 HasArg = 0,
322 HasMin = 1,
323 HasMax = 1,
324 HasConj = 1,
325 HasSetLinear = 1,
326 HasSqrt = 1
327 };
328};
329
330template <>
331struct packet_traits<int32_t> : default_packet_traits {
332 typedef Packet4i type;
333 typedef Packet2i half;
334 enum {
335 Vectorizable = 1,
336 AlignedOnScalar = 1,
337 size = 4,
338
339 HasCmp = 1,
340 HasAdd = 1,
341 HasSub = 1,
342 HasShift = 1,
343 HasMul = 1,
344 HasNegate = 1,
345 HasAbs = 1,
346 HasArg = 0,
347 HasAbsDiff = 1,
348 HasMin = 1,
349 HasMax = 1,
350 HasConj = 1,
351 HasSetLinear = 1,
352 };
353};
354
355template <>
356struct packet_traits<uint32_t> : default_packet_traits {
357 typedef Packet4ui type;
358 typedef Packet2ui half;
359 enum {
360 Vectorizable = 1,
361 AlignedOnScalar = 1,
362 size = 4,
363
364 HasCmp = 1,
365 HasAdd = 1,
366 HasSub = 1,
367 HasShift = 1,
368 HasMul = 1,
369 HasNegate = 0,
370 HasAbs = 1,
371 HasArg = 0,
372 HasAbsDiff = 1,
373 HasMin = 1,
374 HasMax = 1,
375 HasConj = 1,
376 HasSetLinear = 1,
377
378 HasSqrt = 1
379 };
380};
381
382template <>
383struct packet_traits<int64_t> : default_packet_traits {
384 typedef Packet2l type;
385 typedef Packet2l half;
386 enum {
387 Vectorizable = 1,
388 AlignedOnScalar = 1,
389 size = 2,
390
391 HasCmp = 1,
392 HasAdd = 1,
393 HasSub = 1,
394 HasShift = 1,
395 HasMul = 1,
396 HasNegate = 1,
397 HasAbs = 1,
398 HasArg = 0,
399 HasAbsDiff = 1,
400 HasMin = 1,
401 HasMax = 1,
402 HasConj = 1,
403 HasSetLinear = 1,
404 };
405};
406
407template <>
408struct packet_traits<uint64_t> : default_packet_traits {
409 typedef Packet2ul type;
410 typedef Packet2ul half;
411 enum {
412 Vectorizable = 1,
413 AlignedOnScalar = 1,
414 size = 2,
415
416 HasCmp = 1,
417 HasAdd = 1,
418 HasSub = 1,
419 HasShift = 1,
420 HasMul = 1,
421 HasNegate = 0,
422 HasAbs = 1,
423 HasArg = 0,
424 HasAbsDiff = 1,
425 HasMin = 1,
426 HasMax = 1,
427 HasConj = 1,
428 HasSetLinear = 1,
429 };
430};
431
432template <typename Packet, typename Scalar>
433struct neon_unpacket_default {
434 using type = Scalar;
435 using half = Packet;
436 static constexpr int size = sizeof(Packet) / sizeof(Scalar);
437 static constexpr int alignment = sizeof(Packet);
438 static constexpr bool vectorizable = true;
439 static constexpr bool masked_load_available = false;
440 static constexpr bool masked_store_available = false;
441};
442
443template <>
444struct unpacket_traits<Packet2f> : neon_unpacket_default<Packet2f, float> {
445 using integer_packet = Packet2i;
446};
447template <>
448struct unpacket_traits<Packet4f> : neon_unpacket_default<Packet4f, float> {
449 using half = Packet2f;
450 using integer_packet = Packet4i;
451};
452template <>
453struct unpacket_traits<Packet4c> : neon_unpacket_default<Packet4c, int8_t> {};
454template <>
455struct unpacket_traits<Packet8c> : neon_unpacket_default<Packet8c, int8_t> {
456 using half = Packet4c;
457};
458template <>
459struct unpacket_traits<Packet16c> : neon_unpacket_default<Packet16c, int8_t> {
460 using half = Packet8c;
461};
462template <>
463struct unpacket_traits<Packet4uc> : neon_unpacket_default<Packet4uc, uint8_t> {};
464template <>
465struct unpacket_traits<Packet8uc> : neon_unpacket_default<Packet8uc, uint8_t> {
466 using half = Packet4uc;
467};
468template <>
469struct unpacket_traits<Packet16uc> : neon_unpacket_default<Packet16uc, uint8_t> {
470 using half = Packet8uc;
471};
472template <>
473struct unpacket_traits<Packet4s> : neon_unpacket_default<Packet4s, int16_t> {};
474template <>
475struct unpacket_traits<Packet8s> : neon_unpacket_default<Packet8s, int16_t> {
476 using half = Packet4s;
477};
478template <>
479struct unpacket_traits<Packet4us> : neon_unpacket_default<Packet4us, uint16_t> {};
480template <>
481struct unpacket_traits<Packet8us> : neon_unpacket_default<Packet8us, uint16_t> {
482 using half = Packet4us;
483};
484template <>
485struct unpacket_traits<Packet2i> : neon_unpacket_default<Packet2i, int32_t> {};
486template <>
487struct unpacket_traits<Packet4i> : neon_unpacket_default<Packet4i, int32_t> {
488 using half = Packet2i;
489};
490template <>
491struct unpacket_traits<Packet2ui> : neon_unpacket_default<Packet2ui, uint32_t> {};
492template <>
493struct unpacket_traits<Packet4ui> : neon_unpacket_default<Packet4ui, uint32_t> {
494 using half = Packet2ui;
495};
496template <>
497struct unpacket_traits<Packet2l> : neon_unpacket_default<Packet2l, int64_t> {};
498template <>
499struct unpacket_traits<Packet2ul> : neon_unpacket_default<Packet2ul, uint64_t> {};
500
501template <>
502EIGEN_STRONG_INLINE Packet2f pzero(const Packet2f& /*a*/) {
503 return vdup_n_f32(0.0f);
504}
505
506template <>
507EIGEN_STRONG_INLINE Packet4f pzero(const Packet4f& /*a*/) {
508 return vdupq_n_f32(0.0f);
509}
510
511template <>
512EIGEN_STRONG_INLINE Packet2f pset1<Packet2f>(const float& from) {
513 return vdup_n_f32(from);
514}
515template <>
516EIGEN_STRONG_INLINE Packet4f pset1<Packet4f>(const float& from) {
517 return vdupq_n_f32(from);
518}
519template <>
520EIGEN_STRONG_INLINE Packet4c pset1<Packet4c>(const int8_t& from) {
521 return vget_lane_s32(vreinterpret_s32_s8(vdup_n_s8(from)), 0);
522}
523template <>
524EIGEN_STRONG_INLINE Packet8c pset1<Packet8c>(const int8_t& from) {
525 return vdup_n_s8(from);
526}
527template <>
528EIGEN_STRONG_INLINE Packet16c pset1<Packet16c>(const int8_t& from) {
529 return vdupq_n_s8(from);
530}
531template <>
532EIGEN_STRONG_INLINE Packet4uc pset1<Packet4uc>(const uint8_t& from) {
533 return vget_lane_u32(vreinterpret_u32_u8(vdup_n_u8(from)), 0);
534}
535template <>
536EIGEN_STRONG_INLINE Packet8uc pset1<Packet8uc>(const uint8_t& from) {
537 return vdup_n_u8(from);
538}
539template <>
540EIGEN_STRONG_INLINE Packet16uc pset1<Packet16uc>(const uint8_t& from) {
541 return vdupq_n_u8(from);
542}
543template <>
544EIGEN_STRONG_INLINE Packet4s pset1<Packet4s>(const int16_t& from) {
545 return vdup_n_s16(from);
546}
547template <>
548EIGEN_STRONG_INLINE Packet8s pset1<Packet8s>(const int16_t& from) {
549 return vdupq_n_s16(from);
550}
551template <>
552EIGEN_STRONG_INLINE Packet4us pset1<Packet4us>(const uint16_t& from) {
553 return vdup_n_u16(from);
554}
555template <>
556EIGEN_STRONG_INLINE Packet8us pset1<Packet8us>(const uint16_t& from) {
557 return vdupq_n_u16(from);
558}
559template <>
560EIGEN_STRONG_INLINE Packet2i pset1<Packet2i>(const int32_t& from) {
561 return vdup_n_s32(from);
562}
563template <>
564EIGEN_STRONG_INLINE Packet4i pset1<Packet4i>(const int32_t& from) {
565 return vdupq_n_s32(from);
566}
567template <>
568EIGEN_STRONG_INLINE Packet2ui pset1<Packet2ui>(const uint32_t& from) {
569 return vdup_n_u32(from);
570}
571template <>
572EIGEN_STRONG_INLINE Packet4ui pset1<Packet4ui>(const uint32_t& from) {
573 return vdupq_n_u32(from);
574}
575template <>
576EIGEN_STRONG_INLINE Packet2l pset1<Packet2l>(const int64_t& from) {
577 return vdupq_n_s64(from);
578}
579template <>
580EIGEN_STRONG_INLINE Packet2ul pset1<Packet2ul>(const uint64_t& from) {
581 return vdupq_n_u64(from);
582}
583
584template <>
585EIGEN_STRONG_INLINE Packet2f pset1frombits<Packet2f>(uint32_t from) {
586 return vreinterpret_f32_u32(vdup_n_u32(from));
587}
588template <>
589EIGEN_STRONG_INLINE Packet4f pset1frombits<Packet4f>(uint32_t from) {
590 return vreinterpretq_f32_u32(vdupq_n_u32(from));
591}
592
593template <>
594EIGEN_STRONG_INLINE Packet2f plset<Packet2f>(const float& a) {
595 const float c[] = {0.0f, 1.0f};
596 return vadd_f32(pset1<Packet2f>(a), vld1_f32(c));
597}
598template <>
599EIGEN_STRONG_INLINE Packet4f plset<Packet4f>(const float& a) {
600 const float c[] = {0.0f, 1.0f, 2.0f, 3.0f};
601 return vaddq_f32(pset1<Packet4f>(a), vld1q_f32(c));
602}
603template <>
604EIGEN_STRONG_INLINE Packet4c plset<Packet4c>(const int8_t& a) {
605 return vget_lane_s32(vreinterpret_s32_s8(vadd_s8(vreinterpret_s8_u32(vdup_n_u32(0x03020100)), vdup_n_s8(a))), 0);
606}
607template <>
608EIGEN_STRONG_INLINE Packet8c plset<Packet8c>(const int8_t& a) {
609 const int8_t c[] = {0, 1, 2, 3, 4, 5, 6, 7};
610 return vadd_s8(pset1<Packet8c>(a), vld1_s8(c));
611}
612template <>
613EIGEN_STRONG_INLINE Packet16c plset<Packet16c>(const int8_t& a) {
614 const int8_t c[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
615 return vaddq_s8(pset1<Packet16c>(a), vld1q_s8(c));
616}
617template <>
618EIGEN_STRONG_INLINE Packet4uc plset<Packet4uc>(const uint8_t& a) {
619 return vget_lane_u32(vreinterpret_u32_u8(vadd_u8(vreinterpret_u8_u32(vdup_n_u32(0x03020100)), vdup_n_u8(a))), 0);
620}
621template <>
622EIGEN_STRONG_INLINE Packet8uc plset<Packet8uc>(const uint8_t& a) {
623 const uint8_t c[] = {0, 1, 2, 3, 4, 5, 6, 7};
624 return vadd_u8(pset1<Packet8uc>(a), vld1_u8(c));
625}
626template <>
627EIGEN_STRONG_INLINE Packet16uc plset<Packet16uc>(const uint8_t& a) {
628 const uint8_t c[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
629 return vaddq_u8(pset1<Packet16uc>(a), vld1q_u8(c));
630}
631template <>
632EIGEN_STRONG_INLINE Packet4s plset<Packet4s>(const int16_t& a) {
633 const int16_t c[] = {0, 1, 2, 3};
634 return vadd_s16(pset1<Packet4s>(a), vld1_s16(c));
635}
636template <>
637EIGEN_STRONG_INLINE Packet4us plset<Packet4us>(const uint16_t& a) {
638 const uint16_t c[] = {0, 1, 2, 3};
639 return vadd_u16(pset1<Packet4us>(a), vld1_u16(c));
640}
641template <>
642EIGEN_STRONG_INLINE Packet8s plset<Packet8s>(const int16_t& a) {
643 const int16_t c[] = {0, 1, 2, 3, 4, 5, 6, 7};
644 return vaddq_s16(pset1<Packet8s>(a), vld1q_s16(c));
645}
646template <>
647EIGEN_STRONG_INLINE Packet8us plset<Packet8us>(const uint16_t& a) {
648 const uint16_t c[] = {0, 1, 2, 3, 4, 5, 6, 7};
649 return vaddq_u16(pset1<Packet8us>(a), vld1q_u16(c));
650}
651template <>
652EIGEN_STRONG_INLINE Packet2i plset<Packet2i>(const int32_t& a) {
653 const int32_t c[] = {0, 1};
654 return vadd_s32(pset1<Packet2i>(a), vld1_s32(c));
655}
656template <>
657EIGEN_STRONG_INLINE Packet4i plset<Packet4i>(const int32_t& a) {
658 const int32_t c[] = {0, 1, 2, 3};
659 return vaddq_s32(pset1<Packet4i>(a), vld1q_s32(c));
660}
661template <>
662EIGEN_STRONG_INLINE Packet2ui plset<Packet2ui>(const uint32_t& a) {
663 const uint32_t c[] = {0, 1};
664 return vadd_u32(pset1<Packet2ui>(a), vld1_u32(c));
665}
666template <>
667EIGEN_STRONG_INLINE Packet4ui plset<Packet4ui>(const uint32_t& a) {
668 const uint32_t c[] = {0, 1, 2, 3};
669 return vaddq_u32(pset1<Packet4ui>(a), vld1q_u32(c));
670}
671template <>
672EIGEN_STRONG_INLINE Packet2l plset<Packet2l>(const int64_t& a) {
673 const int64_t c[] = {0, 1};
674 return vaddq_s64(pset1<Packet2l>(a), vld1q_s64(c));
675}
676template <>
677EIGEN_STRONG_INLINE Packet2ul plset<Packet2ul>(const uint64_t& a) {
678 const uint64_t c[] = {0, 1};
679 return vaddq_u64(pset1<Packet2ul>(a), vld1q_u64(c));
680}
681
682template <>
683EIGEN_STRONG_INLINE Packet2f padd<Packet2f>(const Packet2f& a, const Packet2f& b) {
684 return vadd_f32(a, b);
685}
686template <>
687EIGEN_STRONG_INLINE Packet4f padd<Packet4f>(const Packet4f& a, const Packet4f& b) {
688 return vaddq_f32(a, b);
689}
690template <>
691EIGEN_STRONG_INLINE Packet4c padd<Packet4c>(const Packet4c& a, const Packet4c& b) {
692 return vget_lane_s32(
693 vreinterpret_s32_s8(vadd_s8(vreinterpret_s8_s32(vdup_n_s32(a)), vreinterpret_s8_s32(vdup_n_s32(b)))), 0);
694}
695template <>
696EIGEN_STRONG_INLINE Packet8c padd<Packet8c>(const Packet8c& a, const Packet8c& b) {
697 return vadd_s8(a, b);
698}
699template <>
700EIGEN_STRONG_INLINE Packet16c padd<Packet16c>(const Packet16c& a, const Packet16c& b) {
701 return vaddq_s8(a, b);
702}
703template <>
704EIGEN_STRONG_INLINE Packet4uc padd<Packet4uc>(const Packet4uc& a, const Packet4uc& b) {
705 return vget_lane_u32(
706 vreinterpret_u32_u8(vadd_u8(vreinterpret_u8_u32(vdup_n_u32(a)), vreinterpret_u8_u32(vdup_n_u32(b)))), 0);
707}
708template <>
709EIGEN_STRONG_INLINE Packet8uc padd<Packet8uc>(const Packet8uc& a, const Packet8uc& b) {
710 return vadd_u8(a, b);
711}
712template <>
713EIGEN_STRONG_INLINE Packet16uc padd<Packet16uc>(const Packet16uc& a, const Packet16uc& b) {
714 return vaddq_u8(a, b);
715}
716template <>
717EIGEN_STRONG_INLINE Packet4s padd<Packet4s>(const Packet4s& a, const Packet4s& b) {
718 return vadd_s16(a, b);
719}
720template <>
721EIGEN_STRONG_INLINE Packet8s padd<Packet8s>(const Packet8s& a, const Packet8s& b) {
722 return vaddq_s16(a, b);
723}
724template <>
725EIGEN_STRONG_INLINE Packet4us padd<Packet4us>(const Packet4us& a, const Packet4us& b) {
726 return vadd_u16(a, b);
727}
728template <>
729EIGEN_STRONG_INLINE Packet8us padd<Packet8us>(const Packet8us& a, const Packet8us& b) {
730 return vaddq_u16(a, b);
731}
732template <>
733EIGEN_STRONG_INLINE Packet2i padd<Packet2i>(const Packet2i& a, const Packet2i& b) {
734 return vadd_s32(a, b);
735}
736template <>
737EIGEN_STRONG_INLINE Packet4i padd<Packet4i>(const Packet4i& a, const Packet4i& b) {
738 return vaddq_s32(a, b);
739}
740template <>
741EIGEN_STRONG_INLINE Packet2ui padd<Packet2ui>(const Packet2ui& a, const Packet2ui& b) {
742 return vadd_u32(a, b);
743}
744template <>
745EIGEN_STRONG_INLINE Packet4ui padd<Packet4ui>(const Packet4ui& a, const Packet4ui& b) {
746 return vaddq_u32(a, b);
747}
748template <>
749EIGEN_STRONG_INLINE Packet2l padd<Packet2l>(const Packet2l& a, const Packet2l& b) {
750 return vaddq_s64(a, b);
751}
752template <>
753EIGEN_STRONG_INLINE Packet2ul padd<Packet2ul>(const Packet2ul& a, const Packet2ul& b) {
754 return vaddq_u64(a, b);
755}
756
757template <>
758EIGEN_STRONG_INLINE Packet2f psub<Packet2f>(const Packet2f& a, const Packet2f& b) {
759 return vsub_f32(a, b);
760}
761template <>
762EIGEN_STRONG_INLINE Packet4f psub<Packet4f>(const Packet4f& a, const Packet4f& b) {
763 return vsubq_f32(a, b);
764}
765template <>
766EIGEN_STRONG_INLINE Packet4c psub<Packet4c>(const Packet4c& a, const Packet4c& b) {
767 return vget_lane_s32(
768 vreinterpret_s32_s8(vsub_s8(vreinterpret_s8_s32(vdup_n_s32(a)), vreinterpret_s8_s32(vdup_n_s32(b)))), 0);
769}
770template <>
771EIGEN_STRONG_INLINE Packet8c psub<Packet8c>(const Packet8c& a, const Packet8c& b) {
772 return vsub_s8(a, b);
773}
774template <>
775EIGEN_STRONG_INLINE Packet16c psub<Packet16c>(const Packet16c& a, const Packet16c& b) {
776 return vsubq_s8(a, b);
777}
778template <>
779EIGEN_STRONG_INLINE Packet4uc psub<Packet4uc>(const Packet4uc& a, const Packet4uc& b) {
780 return vget_lane_u32(
781 vreinterpret_u32_u8(vsub_u8(vreinterpret_u8_u32(vdup_n_u32(a)), vreinterpret_u8_u32(vdup_n_u32(b)))), 0);
782}
783template <>
784EIGEN_STRONG_INLINE Packet8uc psub<Packet8uc>(const Packet8uc& a, const Packet8uc& b) {
785 return vsub_u8(a, b);
786}
787template <>
788EIGEN_STRONG_INLINE Packet16uc psub<Packet16uc>(const Packet16uc& a, const Packet16uc& b) {
789 return vsubq_u8(a, b);
790}
791template <>
792EIGEN_STRONG_INLINE Packet4s psub<Packet4s>(const Packet4s& a, const Packet4s& b) {
793 return vsub_s16(a, b);
794}
795template <>
796EIGEN_STRONG_INLINE Packet8s psub<Packet8s>(const Packet8s& a, const Packet8s& b) {
797 return vsubq_s16(a, b);
798}
799template <>
800EIGEN_STRONG_INLINE Packet4us psub<Packet4us>(const Packet4us& a, const Packet4us& b) {
801 return vsub_u16(a, b);
802}
803template <>
804EIGEN_STRONG_INLINE Packet8us psub<Packet8us>(const Packet8us& a, const Packet8us& b) {
805 return vsubq_u16(a, b);
806}
807template <>
808EIGEN_STRONG_INLINE Packet2i psub<Packet2i>(const Packet2i& a, const Packet2i& b) {
809 return vsub_s32(a, b);
810}
811template <>
812EIGEN_STRONG_INLINE Packet4i psub<Packet4i>(const Packet4i& a, const Packet4i& b) {
813 return vsubq_s32(a, b);
814}
815template <>
816EIGEN_STRONG_INLINE Packet2ui psub<Packet2ui>(const Packet2ui& a, const Packet2ui& b) {
817 return vsub_u32(a, b);
818}
819template <>
820EIGEN_STRONG_INLINE Packet4ui psub<Packet4ui>(const Packet4ui& a, const Packet4ui& b) {
821 return vsubq_u32(a, b);
822}
823template <>
824EIGEN_STRONG_INLINE Packet2l psub<Packet2l>(const Packet2l& a, const Packet2l& b) {
825 return vsubq_s64(a, b);
826}
827template <>
828EIGEN_STRONG_INLINE Packet2ul psub<Packet2ul>(const Packet2ul& a, const Packet2ul& b) {
829 return vsubq_u64(a, b);
830}
831
832template <>
833EIGEN_STRONG_INLINE Packet2f pxor<Packet2f>(const Packet2f& a, const Packet2f& b);
834template <>
835EIGEN_STRONG_INLINE Packet2f paddsub<Packet2f>(const Packet2f& a, const Packet2f& b) {
836 Packet2f mask = make_packet2f(numext::bit_cast<float>(0x80000000u), 0.0f);
837 return padd(a, pxor(mask, b));
838}
839template <>
840EIGEN_STRONG_INLINE Packet4f pxor<Packet4f>(const Packet4f& a, const Packet4f& b);
841template <>
842EIGEN_STRONG_INLINE Packet4f paddsub<Packet4f>(const Packet4f& a, const Packet4f& b) {
843 Packet4f mask = make_packet4f(numext::bit_cast<float>(0x80000000u), 0.0f, numext::bit_cast<float>(0x80000000u), 0.0f);
844 return padd(a, pxor(mask, b));
845}
846
847template <>
848EIGEN_STRONG_INLINE Packet2f pnegate(const Packet2f& a) {
849 return vneg_f32(a);
850}
851template <>
852EIGEN_STRONG_INLINE Packet4f pnegate(const Packet4f& a) {
853 return vnegq_f32(a);
854}
855template <>
856EIGEN_STRONG_INLINE Packet4c pnegate(const Packet4c& a) {
857 return vget_lane_s32(vreinterpret_s32_s8(vneg_s8(vreinterpret_s8_s32(vdup_n_s32(a)))), 0);
858}
859template <>
860EIGEN_STRONG_INLINE Packet8c pnegate(const Packet8c& a) {
861 return vneg_s8(a);
862}
863template <>
864EIGEN_STRONG_INLINE Packet16c pnegate(const Packet16c& a) {
865 return vnegq_s8(a);
866}
867template <>
868EIGEN_STRONG_INLINE Packet4s pnegate(const Packet4s& a) {
869 return vneg_s16(a);
870}
871template <>
872EIGEN_STRONG_INLINE Packet8s pnegate(const Packet8s& a) {
873 return vnegq_s16(a);
874}
875template <>
876EIGEN_STRONG_INLINE Packet2i pnegate(const Packet2i& a) {
877 return vneg_s32(a);
878}
879template <>
880EIGEN_STRONG_INLINE Packet4i pnegate(const Packet4i& a) {
881 return vnegq_s32(a);
882}
883template <>
884EIGEN_STRONG_INLINE Packet2l pnegate(const Packet2l& a) {
885#if EIGEN_ARCH_ARM64
886 return vnegq_s64(a);
887#elif !EIGEN_GNUC_STRICT_AT_LEAST(12, 0, 0)
888 return psub(pzero(a), a);
889#else
890 // NOTE: GCC>=12 refuses to emit `vsub.i64` for `0 - x`: <https://godbolt.org/z/bfaz9ao59>.
891 int64x2_t x = a;
892 int64x2_t z = vdupq_n_s64(0);
893 asm("vsub.i64 %q0, %q1, %q0" : "+w"(x) : "w"(z));
894 return x;
895#endif
896}
897
898template <>
899EIGEN_STRONG_INLINE Packet2f pmul<Packet2f>(const Packet2f& a, const Packet2f& b) {
900 return vmul_f32(a, b);
901}
902template <>
903EIGEN_STRONG_INLINE Packet4f pmul<Packet4f>(const Packet4f& a, const Packet4f& b) {
904 return vmulq_f32(a, b);
905}
906template <>
907EIGEN_STRONG_INLINE Packet4c pmul<Packet4c>(const Packet4c& a, const Packet4c& b) {
908 return vget_lane_s32(
909 vreinterpret_s32_s8(vmul_s8(vreinterpret_s8_s32(vdup_n_s32(a)), vreinterpret_s8_s32(vdup_n_s32(b)))), 0);
910}
911template <>
912EIGEN_STRONG_INLINE Packet8c pmul<Packet8c>(const Packet8c& a, const Packet8c& b) {
913 return vmul_s8(a, b);
914}
915template <>
916EIGEN_STRONG_INLINE Packet16c pmul<Packet16c>(const Packet16c& a, const Packet16c& b) {
917 return vmulq_s8(a, b);
918}
919template <>
920EIGEN_STRONG_INLINE Packet4uc pmul<Packet4uc>(const Packet4uc& a, const Packet4uc& b) {
921 return vget_lane_u32(
922 vreinterpret_u32_u8(vmul_u8(vreinterpret_u8_u32(vdup_n_u32(a)), vreinterpret_u8_u32(vdup_n_u32(b)))), 0);
923}
924template <>
925EIGEN_STRONG_INLINE Packet8uc pmul<Packet8uc>(const Packet8uc& a, const Packet8uc& b) {
926 return vmul_u8(a, b);
927}
928template <>
929EIGEN_STRONG_INLINE Packet16uc pmul<Packet16uc>(const Packet16uc& a, const Packet16uc& b) {
930 return vmulq_u8(a, b);
931}
932template <>
933EIGEN_STRONG_INLINE Packet4s pmul<Packet4s>(const Packet4s& a, const Packet4s& b) {
934 return vmul_s16(a, b);
935}
936template <>
937EIGEN_STRONG_INLINE Packet8s pmul<Packet8s>(const Packet8s& a, const Packet8s& b) {
938 return vmulq_s16(a, b);
939}
940template <>
941EIGEN_STRONG_INLINE Packet4us pmul<Packet4us>(const Packet4us& a, const Packet4us& b) {
942 return vmul_u16(a, b);
943}
944template <>
945EIGEN_STRONG_INLINE Packet8us pmul<Packet8us>(const Packet8us& a, const Packet8us& b) {
946 return vmulq_u16(a, b);
947}
948template <>
949EIGEN_STRONG_INLINE Packet2i pmul<Packet2i>(const Packet2i& a, const Packet2i& b) {
950 return vmul_s32(a, b);
951}
952template <>
953EIGEN_STRONG_INLINE Packet4i pmul<Packet4i>(const Packet4i& a, const Packet4i& b) {
954 return vmulq_s32(a, b);
955}
956template <>
957EIGEN_STRONG_INLINE Packet2ui pmul<Packet2ui>(const Packet2ui& a, const Packet2ui& b) {
958 return vmul_u32(a, b);
959}
960template <>
961EIGEN_STRONG_INLINE Packet4ui pmul<Packet4ui>(const Packet4ui& a, const Packet4ui& b) {
962 return vmulq_u32(a, b);
963}
964template <>
965EIGEN_STRONG_INLINE Packet2ul pmul<Packet2ul>(const Packet2ul& a, const Packet2ul& b) {
966 const uint32x2_t al = vmovn_u64(a);
967 const uint32x2_t bl = vmovn_u64(b);
968 const uint64x2_t hi = vpaddlq_u32(vmulq_u32(vreinterpretq_u32_u64(a), vrev64q_u32(vreinterpretq_u32_u64(b))));
969 return vmlal_u32(vshlq_n_u64(hi, 32), al, bl);
970}
971template <>
972EIGEN_STRONG_INLINE Packet2l pmul<Packet2l>(const Packet2l& a, const Packet2l& b) {
973 return vreinterpretq_s64_u64(pmul(vreinterpretq_u64_s64(a), vreinterpretq_u64_s64(b)));
974}
975
976template <>
977EIGEN_STRONG_INLINE Packet4c pdiv<Packet4c>(const Packet4c& /*a*/, const Packet4c& /*b*/) {
978 eigen_assert(false && "packet integer division are not supported by NEON");
979 return pset1<Packet4c>(0);
980}
981template <>
982EIGEN_STRONG_INLINE Packet8c pdiv<Packet8c>(const Packet8c& /*a*/, const Packet8c& /*b*/) {
983 eigen_assert(false && "packet integer division are not supported by NEON");
984 return pset1<Packet8c>(0);
985}
986template <>
987EIGEN_STRONG_INLINE Packet16c pdiv<Packet16c>(const Packet16c& /*a*/, const Packet16c& /*b*/) {
988 eigen_assert(false && "packet integer division are not supported by NEON");
989 return pset1<Packet16c>(0);
990}
991template <>
992EIGEN_STRONG_INLINE Packet4uc pdiv<Packet4uc>(const Packet4uc& /*a*/, const Packet4uc& /*b*/) {
993 eigen_assert(false && "packet integer division are not supported by NEON");
994 return pset1<Packet4uc>(0);
995}
996template <>
997EIGEN_STRONG_INLINE Packet8uc pdiv<Packet8uc>(const Packet8uc& /*a*/, const Packet8uc& /*b*/) {
998 eigen_assert(false && "packet integer division are not supported by NEON");
999 return pset1<Packet8uc>(0);
1000}
1001template <>
1002EIGEN_STRONG_INLINE Packet16uc pdiv<Packet16uc>(const Packet16uc& /*a*/, const Packet16uc& /*b*/) {
1003 eigen_assert(false && "packet integer division are not supported by NEON");
1004 return pset1<Packet16uc>(0);
1005}
1006template <>
1007EIGEN_STRONG_INLINE Packet4s pdiv<Packet4s>(const Packet4s& /*a*/, const Packet4s& /*b*/) {
1008 eigen_assert(false && "packet integer division are not supported by NEON");
1009 return pset1<Packet4s>(0);
1010}
1011template <>
1012EIGEN_STRONG_INLINE Packet8s pdiv<Packet8s>(const Packet8s& /*a*/, const Packet8s& /*b*/) {
1013 eigen_assert(false && "packet integer division are not supported by NEON");
1014 return pset1<Packet8s>(0);
1015}
1016template <>
1017EIGEN_STRONG_INLINE Packet4us pdiv<Packet4us>(const Packet4us& /*a*/, const Packet4us& /*b*/) {
1018 eigen_assert(false && "packet integer division are not supported by NEON");
1019 return pset1<Packet4us>(0);
1020}
1021template <>
1022EIGEN_STRONG_INLINE Packet8us pdiv<Packet8us>(const Packet8us& /*a*/, const Packet8us& /*b*/) {
1023 eigen_assert(false && "packet integer division are not supported by NEON");
1024 return pset1<Packet8us>(0);
1025}
1026template <>
1027EIGEN_STRONG_INLINE Packet2i pdiv<Packet2i>(const Packet2i& /*a*/, const Packet2i& /*b*/) {
1028 eigen_assert(false && "packet integer division are not supported by NEON");
1029 return pset1<Packet2i>(0);
1030}
1031template <>
1032EIGEN_STRONG_INLINE Packet4i pdiv<Packet4i>(const Packet4i& /*a*/, const Packet4i& /*b*/) {
1033 eigen_assert(false && "packet integer division are not supported by NEON");
1034 return pset1<Packet4i>(0);
1035}
1036template <>
1037EIGEN_STRONG_INLINE Packet2ui pdiv<Packet2ui>(const Packet2ui& /*a*/, const Packet2ui& /*b*/) {
1038 eigen_assert(false && "packet integer division are not supported by NEON");
1039 return pset1<Packet2ui>(0);
1040}
1041template <>
1042EIGEN_STRONG_INLINE Packet4ui pdiv<Packet4ui>(const Packet4ui& /*a*/, const Packet4ui& /*b*/) {
1043 eigen_assert(false && "packet integer division are not supported by NEON");
1044 return pset1<Packet4ui>(0);
1045}
1046template <>
1047EIGEN_STRONG_INLINE Packet2l pdiv<Packet2l>(const Packet2l& /*a*/, const Packet2l& /*b*/) {
1048 eigen_assert(false && "packet integer division are not supported by NEON");
1049 return pset1<Packet2l>(0LL);
1050}
1051template <>
1052EIGEN_STRONG_INLINE Packet2ul pdiv<Packet2ul>(const Packet2ul& /*a*/, const Packet2ul& /*b*/) {
1053 eigen_assert(false && "packet integer division are not supported by NEON");
1054 return pset1<Packet2ul>(0ULL);
1055}
1056
1057#ifdef EIGEN_VECTORIZE_FMA
1058template <>
1059EIGEN_STRONG_INLINE Packet4f pmadd(const Packet4f& a, const Packet4f& b, const Packet4f& c) {
1060 return vfmaq_f32(c, a, b);
1061}
1062template <>
1063EIGEN_STRONG_INLINE Packet2f pmadd(const Packet2f& a, const Packet2f& b, const Packet2f& c) {
1064 return vfma_f32(c, a, b);
1065}
1066template <>
1067EIGEN_STRONG_INLINE Packet4f pnmadd(const Packet4f& a, const Packet4f& b, const Packet4f& c) {
1068 return vfmsq_f32(c, a, b);
1069}
1070template <>
1071EIGEN_STRONG_INLINE Packet2f pnmadd(const Packet2f& a, const Packet2f& b, const Packet2f& c) {
1072 return vfms_f32(c, a, b);
1073}
1074#else
1075template <>
1076EIGEN_STRONG_INLINE Packet4f pmadd(const Packet4f& a, const Packet4f& b, const Packet4f& c) {
1077 return vmlaq_f32(c, a, b);
1078}
1079template <>
1080EIGEN_STRONG_INLINE Packet2f pmadd(const Packet2f& a, const Packet2f& b, const Packet2f& c) {
1081 return vmla_f32(c, a, b);
1082}
1083template <>
1084EIGEN_STRONG_INLINE Packet4f pnmadd(const Packet4f& a, const Packet4f& b, const Packet4f& c) {
1085 return vmlsq_f32(c, a, b);
1086}
1087template <>
1088EIGEN_STRONG_INLINE Packet2f pnmadd(const Packet2f& a, const Packet2f& b, const Packet2f& c) {
1089 return vmls_f32(c, a, b);
1090}
1091#endif
1092template <>
1093EIGEN_STRONG_INLINE Packet4f pmsub(const Packet4f& a, const Packet4f& b, const Packet4f& c) {
1094 return pnegate(pnmadd(a, b, c));
1095}
1096template <>
1097EIGEN_STRONG_INLINE Packet2f pmsub(const Packet2f& a, const Packet2f& b, const Packet2f& c) {
1098 return pnegate(pnmadd(a, b, c));
1099}
1100template <>
1101EIGEN_STRONG_INLINE Packet4f pnmsub(const Packet4f& a, const Packet4f& b, const Packet4f& c) {
1102 return pnegate(pmadd(a, b, c));
1103}
1104template <>
1105EIGEN_STRONG_INLINE Packet2f pnmsub(const Packet2f& a, const Packet2f& b, const Packet2f& c) {
1106 return pnegate(pmadd(a, b, c));
1107}
1108
1109// No FMA instruction for int, so use MLA unconditionally.
1110template <>
1111EIGEN_STRONG_INLINE Packet4c pmadd(const Packet4c& a, const Packet4c& b, const Packet4c& c) {
1112 return vget_lane_s32(
1113 vreinterpret_s32_s8(vmla_s8(vreinterpret_s8_s32(vdup_n_s32(c)), vreinterpret_s8_s32(vdup_n_s32(a)),
1114 vreinterpret_s8_s32(vdup_n_s32(b)))),
1115 0);
1116}
1117template <>
1118EIGEN_STRONG_INLINE Packet8c pmadd(const Packet8c& a, const Packet8c& b, const Packet8c& c) {
1119 return vmla_s8(c, a, b);
1120}
1121template <>
1122EIGEN_STRONG_INLINE Packet16c pmadd(const Packet16c& a, const Packet16c& b, const Packet16c& c) {
1123 return vmlaq_s8(c, a, b);
1124}
1125template <>
1126EIGEN_STRONG_INLINE Packet4uc pmadd(const Packet4uc& a, const Packet4uc& b, const Packet4uc& c) {
1127 return vget_lane_u32(
1128 vreinterpret_u32_u8(vmla_u8(vreinterpret_u8_u32(vdup_n_u32(c)), vreinterpret_u8_u32(vdup_n_u32(a)),
1129 vreinterpret_u8_u32(vdup_n_u32(b)))),
1130 0);
1131}
1132template <>
1133EIGEN_STRONG_INLINE Packet8uc pmadd(const Packet8uc& a, const Packet8uc& b, const Packet8uc& c) {
1134 return vmla_u8(c, a, b);
1135}
1136template <>
1137EIGEN_STRONG_INLINE Packet16uc pmadd(const Packet16uc& a, const Packet16uc& b, const Packet16uc& c) {
1138 return vmlaq_u8(c, a, b);
1139}
1140template <>
1141EIGEN_STRONG_INLINE Packet4s pmadd(const Packet4s& a, const Packet4s& b, const Packet4s& c) {
1142 return vmla_s16(c, a, b);
1143}
1144template <>
1145EIGEN_STRONG_INLINE Packet8s pmadd(const Packet8s& a, const Packet8s& b, const Packet8s& c) {
1146 return vmlaq_s16(c, a, b);
1147}
1148template <>
1149EIGEN_STRONG_INLINE Packet4us pmadd(const Packet4us& a, const Packet4us& b, const Packet4us& c) {
1150 return vmla_u16(c, a, b);
1151}
1152template <>
1153EIGEN_STRONG_INLINE Packet8us pmadd(const Packet8us& a, const Packet8us& b, const Packet8us& c) {
1154 return vmlaq_u16(c, a, b);
1155}
1156template <>
1157EIGEN_STRONG_INLINE Packet2i pmadd(const Packet2i& a, const Packet2i& b, const Packet2i& c) {
1158 return vmla_s32(c, a, b);
1159}
1160template <>
1161EIGEN_STRONG_INLINE Packet4i pmadd(const Packet4i& a, const Packet4i& b, const Packet4i& c) {
1162 return vmlaq_s32(c, a, b);
1163}
1164template <>
1165EIGEN_STRONG_INLINE Packet2ui pmadd(const Packet2ui& a, const Packet2ui& b, const Packet2ui& c) {
1166 return vmla_u32(c, a, b);
1167}
1168template <>
1169EIGEN_STRONG_INLINE Packet4ui pmadd(const Packet4ui& a, const Packet4ui& b, const Packet4ui& c) {
1170 return vmlaq_u32(c, a, b);
1171}
1172
1173template <>
1174EIGEN_STRONG_INLINE Packet2f pabsdiff<Packet2f>(const Packet2f& a, const Packet2f& b) {
1175 return vabd_f32(a, b);
1176}
1177template <>
1178EIGEN_STRONG_INLINE Packet4f pabsdiff<Packet4f>(const Packet4f& a, const Packet4f& b) {
1179 return vabdq_f32(a, b);
1180}
1181template <>
1182EIGEN_STRONG_INLINE Packet4c pabsdiff<Packet4c>(const Packet4c& a, const Packet4c& b) {
1183 return vget_lane_s32(
1184 vreinterpret_s32_s8(vabd_s8(vreinterpret_s8_s32(vdup_n_s32(a)), vreinterpret_s8_s32(vdup_n_s32(b)))), 0);
1185}
1186template <>
1187EIGEN_STRONG_INLINE Packet8c pabsdiff<Packet8c>(const Packet8c& a, const Packet8c& b) {
1188 return vabd_s8(a, b);
1189}
1190template <>
1191EIGEN_STRONG_INLINE Packet16c pabsdiff<Packet16c>(const Packet16c& a, const Packet16c& b) {
1192 return vabdq_s8(a, b);
1193}
1194template <>
1195EIGEN_STRONG_INLINE Packet4uc pabsdiff<Packet4uc>(const Packet4uc& a, const Packet4uc& b) {
1196 return vget_lane_u32(
1197 vreinterpret_u32_u8(vabd_u8(vreinterpret_u8_u32(vdup_n_u32(a)), vreinterpret_u8_u32(vdup_n_u32(b)))), 0);
1198}
1199template <>
1200EIGEN_STRONG_INLINE Packet8uc pabsdiff<Packet8uc>(const Packet8uc& a, const Packet8uc& b) {
1201 return vabd_u8(a, b);
1202}
1203template <>
1204EIGEN_STRONG_INLINE Packet16uc pabsdiff<Packet16uc>(const Packet16uc& a, const Packet16uc& b) {
1205 return vabdq_u8(a, b);
1206}
1207template <>
1208EIGEN_STRONG_INLINE Packet4s pabsdiff<Packet4s>(const Packet4s& a, const Packet4s& b) {
1209 return vabd_s16(a, b);
1210}
1211template <>
1212EIGEN_STRONG_INLINE Packet8s pabsdiff<Packet8s>(const Packet8s& a, const Packet8s& b) {
1213 return vabdq_s16(a, b);
1214}
1215template <>
1216EIGEN_STRONG_INLINE Packet4us pabsdiff<Packet4us>(const Packet4us& a, const Packet4us& b) {
1217 return vabd_u16(a, b);
1218}
1219template <>
1220EIGEN_STRONG_INLINE Packet8us pabsdiff<Packet8us>(const Packet8us& a, const Packet8us& b) {
1221 return vabdq_u16(a, b);
1222}
1223template <>
1224EIGEN_STRONG_INLINE Packet2i pabsdiff<Packet2i>(const Packet2i& a, const Packet2i& b) {
1225 return vabd_s32(a, b);
1226}
1227template <>
1228EIGEN_STRONG_INLINE Packet4i pabsdiff<Packet4i>(const Packet4i& a, const Packet4i& b) {
1229 return vabdq_s32(a, b);
1230}
1231template <>
1232EIGEN_STRONG_INLINE Packet2ui pabsdiff<Packet2ui>(const Packet2ui& a, const Packet2ui& b) {
1233 return vabd_u32(a, b);
1234}
1235template <>
1236EIGEN_STRONG_INLINE Packet4ui pabsdiff<Packet4ui>(const Packet4ui& a, const Packet4ui& b) {
1237 return vabdq_u32(a, b);
1238}
1239
1240template <>
1241EIGEN_STRONG_INLINE Packet2f pmin<Packet2f>(const Packet2f& a, const Packet2f& b) {
1242 return vmin_f32(a, b);
1243}
1244template <>
1245EIGEN_STRONG_INLINE Packet4f pmin<Packet4f>(const Packet4f& a, const Packet4f& b) {
1246 return vminq_f32(a, b);
1247}
1248
1249#ifdef __ARM_FEATURE_NUMERIC_MAXMIN
1250// numeric max and min are only available if ARM_FEATURE_NUMERIC_MAXMIN is defined (which can only be the case for Armv8
1251// systems).
1252template <>
1253EIGEN_STRONG_INLINE Packet4f pmin<PropagateNumbers, Packet4f>(const Packet4f& a, const Packet4f& b) {
1254 return vminnmq_f32(a, b);
1255}
1256template <>
1257EIGEN_STRONG_INLINE Packet2f pmin<PropagateNumbers, Packet2f>(const Packet2f& a, const Packet2f& b) {
1258 return vminnm_f32(a, b);
1259}
1260#endif
1261
1262template <>
1263struct pminmax_propagates_nan<Packet2f> : bool_constant<true> {};
1264template <>
1265struct pminmax_propagates_nan<Packet4f> : bool_constant<true> {};
1266
1267template <>
1268EIGEN_STRONG_INLINE Packet4c pmin<Packet4c>(const Packet4c& a, const Packet4c& b) {
1269 return vget_lane_s32(
1270 vreinterpret_s32_s8(vmin_s8(vreinterpret_s8_s32(vdup_n_s32(a)), vreinterpret_s8_s32(vdup_n_s32(b)))), 0);
1271}
1272template <>
1273EIGEN_STRONG_INLINE Packet8c pmin<Packet8c>(const Packet8c& a, const Packet8c& b) {
1274 return vmin_s8(a, b);
1275}
1276template <>
1277EIGEN_STRONG_INLINE Packet16c pmin<Packet16c>(const Packet16c& a, const Packet16c& b) {
1278 return vminq_s8(a, b);
1279}
1280template <>
1281EIGEN_STRONG_INLINE Packet4uc pmin<Packet4uc>(const Packet4uc& a, const Packet4uc& b) {
1282 return vget_lane_u32(
1283 vreinterpret_u32_u8(vmin_u8(vreinterpret_u8_u32(vdup_n_u32(a)), vreinterpret_u8_u32(vdup_n_u32(b)))), 0);
1284}
1285template <>
1286EIGEN_STRONG_INLINE Packet8uc pmin<Packet8uc>(const Packet8uc& a, const Packet8uc& b) {
1287 return vmin_u8(a, b);
1288}
1289template <>
1290EIGEN_STRONG_INLINE Packet16uc pmin<Packet16uc>(const Packet16uc& a, const Packet16uc& b) {
1291 return vminq_u8(a, b);
1292}
1293template <>
1294EIGEN_STRONG_INLINE Packet4s pmin<Packet4s>(const Packet4s& a, const Packet4s& b) {
1295 return vmin_s16(a, b);
1296}
1297template <>
1298EIGEN_STRONG_INLINE Packet8s pmin<Packet8s>(const Packet8s& a, const Packet8s& b) {
1299 return vminq_s16(a, b);
1300}
1301template <>
1302EIGEN_STRONG_INLINE Packet4us pmin<Packet4us>(const Packet4us& a, const Packet4us& b) {
1303 return vmin_u16(a, b);
1304}
1305template <>
1306EIGEN_STRONG_INLINE Packet8us pmin<Packet8us>(const Packet8us& a, const Packet8us& b) {
1307 return vminq_u16(a, b);
1308}
1309template <>
1310EIGEN_STRONG_INLINE Packet2i pmin<Packet2i>(const Packet2i& a, const Packet2i& b) {
1311 return vmin_s32(a, b);
1312}
1313template <>
1314EIGEN_STRONG_INLINE Packet4i pmin<Packet4i>(const Packet4i& a, const Packet4i& b) {
1315 return vminq_s32(a, b);
1316}
1317template <>
1318EIGEN_STRONG_INLINE Packet2ui pmin<Packet2ui>(const Packet2ui& a, const Packet2ui& b) {
1319 return vmin_u32(a, b);
1320}
1321template <>
1322EIGEN_STRONG_INLINE Packet4ui pmin<Packet4ui>(const Packet4ui& a, const Packet4ui& b) {
1323 return vminq_u32(a, b);
1324}
1325template <>
1326EIGEN_STRONG_INLINE Packet2ul pmin<Packet2ul>(const Packet2ul& a, const Packet2ul& b) {
1327 return vsubq_u64(a, vqsubq_u64(a, b));
1328}
1329
1330template <>
1331EIGEN_STRONG_INLINE Packet2f pmax<Packet2f>(const Packet2f& a, const Packet2f& b) {
1332 return vmax_f32(a, b);
1333}
1334template <>
1335EIGEN_STRONG_INLINE Packet4f pmax<Packet4f>(const Packet4f& a, const Packet4f& b) {
1336 return vmaxq_f32(a, b);
1337}
1338
1339#ifdef __ARM_FEATURE_NUMERIC_MAXMIN
1340// numeric max and min are only available if ARM_FEATURE_NUMERIC_MAXMIN is defined (which can only be the case for Armv8
1341// systems).
1342template <>
1343EIGEN_STRONG_INLINE Packet4f pmax<PropagateNumbers, Packet4f>(const Packet4f& a, const Packet4f& b) {
1344 return vmaxnmq_f32(a, b);
1345}
1346template <>
1347EIGEN_STRONG_INLINE Packet2f pmax<PropagateNumbers, Packet2f>(const Packet2f& a, const Packet2f& b) {
1348 return vmaxnm_f32(a, b);
1349}
1350#endif
1351
1352template <>
1353EIGEN_STRONG_INLINE Packet4c pmax<Packet4c>(const Packet4c& a, const Packet4c& b) {
1354 return vget_lane_s32(
1355 vreinterpret_s32_s8(vmax_s8(vreinterpret_s8_s32(vdup_n_s32(a)), vreinterpret_s8_s32(vdup_n_s32(b)))), 0);
1356}
1357template <>
1358EIGEN_STRONG_INLINE Packet8c pmax<Packet8c>(const Packet8c& a, const Packet8c& b) {
1359 return vmax_s8(a, b);
1360}
1361template <>
1362EIGEN_STRONG_INLINE Packet16c pmax<Packet16c>(const Packet16c& a, const Packet16c& b) {
1363 return vmaxq_s8(a, b);
1364}
1365template <>
1366EIGEN_STRONG_INLINE Packet4uc pmax<Packet4uc>(const Packet4uc& a, const Packet4uc& b) {
1367 return vget_lane_u32(
1368 vreinterpret_u32_u8(vmax_u8(vreinterpret_u8_u32(vdup_n_u32(a)), vreinterpret_u8_u32(vdup_n_u32(b)))), 0);
1369}
1370template <>
1371EIGEN_STRONG_INLINE Packet8uc pmax<Packet8uc>(const Packet8uc& a, const Packet8uc& b) {
1372 return vmax_u8(a, b);
1373}
1374template <>
1375EIGEN_STRONG_INLINE Packet16uc pmax<Packet16uc>(const Packet16uc& a, const Packet16uc& b) {
1376 return vmaxq_u8(a, b);
1377}
1378template <>
1379EIGEN_STRONG_INLINE Packet4s pmax<Packet4s>(const Packet4s& a, const Packet4s& b) {
1380 return vmax_s16(a, b);
1381}
1382template <>
1383EIGEN_STRONG_INLINE Packet8s pmax<Packet8s>(const Packet8s& a, const Packet8s& b) {
1384 return vmaxq_s16(a, b);
1385}
1386template <>
1387EIGEN_STRONG_INLINE Packet4us pmax<Packet4us>(const Packet4us& a, const Packet4us& b) {
1388 return vmax_u16(a, b);
1389}
1390template <>
1391EIGEN_STRONG_INLINE Packet8us pmax<Packet8us>(const Packet8us& a, const Packet8us& b) {
1392 return vmaxq_u16(a, b);
1393}
1394template <>
1395EIGEN_STRONG_INLINE Packet2i pmax<Packet2i>(const Packet2i& a, const Packet2i& b) {
1396 return vmax_s32(a, b);
1397}
1398template <>
1399EIGEN_STRONG_INLINE Packet4i pmax<Packet4i>(const Packet4i& a, const Packet4i& b) {
1400 return vmaxq_s32(a, b);
1401}
1402template <>
1403EIGEN_STRONG_INLINE Packet2ui pmax<Packet2ui>(const Packet2ui& a, const Packet2ui& b) {
1404 return vmax_u32(a, b);
1405}
1406template <>
1407EIGEN_STRONG_INLINE Packet4ui pmax<Packet4ui>(const Packet4ui& a, const Packet4ui& b) {
1408 return vmaxq_u32(a, b);
1409}
1410template <>
1411EIGEN_STRONG_INLINE Packet2ul pmax<Packet2ul>(const Packet2ul& a, const Packet2ul& b) {
1412 return vaddq_u64(b, vqsubq_u64(a, b));
1413}
1414
1415// GCC defines the ARM32 vcge/vcgt float intrinsics as generic vector comparisons and, unless
1416// -funsafe-math-optimizations is given, expands them one lane at a time through VFP, because Advanced SIMD
1417// flushes subnormal inputs. Emit the Advanced SIMD comparison directly, as Clang does.
1418#if EIGEN_COMP_GNUC_STRICT && !EIGEN_ARCH_ARM64
1419EIGEN_STRONG_INLINE uint32x2_t neon_vcge_f32(float32x2_t a, float32x2_t b) {
1420 uint32x2_t r;
1421 __asm__("vcge.f32 %P0, %P1, %P2" : "=w"(r) : "w"(a), "w"(b));
1422 return r;
1423}
1424EIGEN_STRONG_INLINE uint32x4_t neon_vcgeq_f32(float32x4_t a, float32x4_t b) {
1425 uint32x4_t r;
1426 __asm__("vcge.f32 %q0, %q1, %q2" : "=w"(r) : "w"(a), "w"(b));
1427 return r;
1428}
1429EIGEN_STRONG_INLINE uint32x2_t neon_vcgt_f32(float32x2_t a, float32x2_t b) {
1430 uint32x2_t r;
1431 __asm__("vcgt.f32 %P0, %P1, %P2" : "=w"(r) : "w"(a), "w"(b));
1432 return r;
1433}
1434EIGEN_STRONG_INLINE uint32x4_t neon_vcgtq_f32(float32x4_t a, float32x4_t b) {
1435 uint32x4_t r;
1436 __asm__("vcgt.f32 %q0, %q1, %q2" : "=w"(r) : "w"(a), "w"(b));
1437 return r;
1438}
1439#else
1440EIGEN_STRONG_INLINE uint32x2_t neon_vcge_f32(float32x2_t a, float32x2_t b) { return vcge_f32(a, b); }
1441EIGEN_STRONG_INLINE uint32x4_t neon_vcgeq_f32(float32x4_t a, float32x4_t b) { return vcgeq_f32(a, b); }
1442EIGEN_STRONG_INLINE uint32x2_t neon_vcgt_f32(float32x2_t a, float32x2_t b) { return vcgt_f32(a, b); }
1443EIGEN_STRONG_INLINE uint32x4_t neon_vcgtq_f32(float32x4_t a, float32x4_t b) { return vcgtq_f32(a, b); }
1444#endif
1445
1446template <>
1447EIGEN_STRONG_INLINE Packet2f pcmp_le<Packet2f>(const Packet2f& a, const Packet2f& b) {
1448 return vreinterpret_f32_u32(neon_vcge_f32(b, a));
1449}
1450template <>
1451EIGEN_STRONG_INLINE Packet4f pcmp_le<Packet4f>(const Packet4f& a, const Packet4f& b) {
1452 return vreinterpretq_f32_u32(neon_vcgeq_f32(b, a));
1453}
1454template <>
1455EIGEN_STRONG_INLINE Packet4c pcmp_le<Packet4c>(const Packet4c& a, const Packet4c& b) {
1456 return vget_lane_s32(
1457 vreinterpret_s32_u8(vcle_s8(vreinterpret_s8_s32(vdup_n_s32(a)), vreinterpret_s8_s32(vdup_n_s32(b)))), 0);
1458}
1459template <>
1460EIGEN_STRONG_INLINE Packet8c pcmp_le<Packet8c>(const Packet8c& a, const Packet8c& b) {
1461 return vreinterpret_s8_u8(vcle_s8(a, b));
1462}
1463template <>
1464EIGEN_STRONG_INLINE Packet16c pcmp_le<Packet16c>(const Packet16c& a, const Packet16c& b) {
1465 return vreinterpretq_s8_u8(vcleq_s8(a, b));
1466}
1467template <>
1468EIGEN_STRONG_INLINE Packet4uc pcmp_le<Packet4uc>(const Packet4uc& a, const Packet4uc& b) {
1469 return vget_lane_u32(
1470 vreinterpret_u32_u8(vcle_u8(vreinterpret_u8_u32(vdup_n_u32(a)), vreinterpret_u8_u32(vdup_n_u32(b)))), 0);
1471}
1472template <>
1473EIGEN_STRONG_INLINE Packet8uc pcmp_le<Packet8uc>(const Packet8uc& a, const Packet8uc& b) {
1474 return vcle_u8(a, b);
1475}
1476template <>
1477EIGEN_STRONG_INLINE Packet16uc pcmp_le<Packet16uc>(const Packet16uc& a, const Packet16uc& b) {
1478 return vcleq_u8(a, b);
1479}
1480template <>
1481EIGEN_STRONG_INLINE Packet4s pcmp_le<Packet4s>(const Packet4s& a, const Packet4s& b) {
1482 return vreinterpret_s16_u16(vcle_s16(a, b));
1483}
1484template <>
1485EIGEN_STRONG_INLINE Packet8s pcmp_le<Packet8s>(const Packet8s& a, const Packet8s& b) {
1486 return vreinterpretq_s16_u16(vcleq_s16(a, b));
1487}
1488template <>
1489EIGEN_STRONG_INLINE Packet4us pcmp_le<Packet4us>(const Packet4us& a, const Packet4us& b) {
1490 return vcle_u16(a, b);
1491}
1492template <>
1493EIGEN_STRONG_INLINE Packet8us pcmp_le<Packet8us>(const Packet8us& a, const Packet8us& b) {
1494 return vcleq_u16(a, b);
1495}
1496template <>
1497EIGEN_STRONG_INLINE Packet2i pcmp_le<Packet2i>(const Packet2i& a, const Packet2i& b) {
1498 return vreinterpret_s32_u32(vcle_s32(a, b));
1499}
1500template <>
1501EIGEN_STRONG_INLINE Packet4i pcmp_le<Packet4i>(const Packet4i& a, const Packet4i& b) {
1502 return vreinterpretq_s32_u32(vcleq_s32(a, b));
1503}
1504template <>
1505EIGEN_STRONG_INLINE Packet2ui pcmp_le<Packet2ui>(const Packet2ui& a, const Packet2ui& b) {
1506 return vcle_u32(a, b);
1507}
1508template <>
1509EIGEN_STRONG_INLINE Packet4ui pcmp_le<Packet4ui>(const Packet4ui& a, const Packet4ui& b) {
1510 return vcleq_u32(a, b);
1511}
1512
1513template <>
1514EIGEN_STRONG_INLINE Packet2f pcmp_lt<Packet2f>(const Packet2f& a, const Packet2f& b) {
1515 return vreinterpret_f32_u32(neon_vcgt_f32(b, a));
1516}
1517template <>
1518EIGEN_STRONG_INLINE Packet4f pcmp_lt<Packet4f>(const Packet4f& a, const Packet4f& b) {
1519 return vreinterpretq_f32_u32(neon_vcgtq_f32(b, a));
1520}
1521template <>
1522EIGEN_STRONG_INLINE Packet4c pcmp_lt<Packet4c>(const Packet4c& a, const Packet4c& b) {
1523 return vget_lane_s32(
1524 vreinterpret_s32_u8(vclt_s8(vreinterpret_s8_s32(vdup_n_s32(a)), vreinterpret_s8_s32(vdup_n_s32(b)))), 0);
1525}
1526template <>
1527EIGEN_STRONG_INLINE Packet8c pcmp_lt<Packet8c>(const Packet8c& a, const Packet8c& b) {
1528 return vreinterpret_s8_u8(vclt_s8(a, b));
1529}
1530template <>
1531EIGEN_STRONG_INLINE Packet16c pcmp_lt<Packet16c>(const Packet16c& a, const Packet16c& b) {
1532 return vreinterpretq_s8_u8(vcltq_s8(a, b));
1533}
1534template <>
1535EIGEN_STRONG_INLINE Packet4uc pcmp_lt<Packet4uc>(const Packet4uc& a, const Packet4uc& b) {
1536 return vget_lane_u32(
1537 vreinterpret_u32_u8(vclt_u8(vreinterpret_u8_u32(vdup_n_u32(a)), vreinterpret_u8_u32(vdup_n_u32(b)))), 0);
1538}
1539template <>
1540EIGEN_STRONG_INLINE Packet8uc pcmp_lt<Packet8uc>(const Packet8uc& a, const Packet8uc& b) {
1541 return vclt_u8(a, b);
1542}
1543template <>
1544EIGEN_STRONG_INLINE Packet16uc pcmp_lt<Packet16uc>(const Packet16uc& a, const Packet16uc& b) {
1545 return vcltq_u8(a, b);
1546}
1547template <>
1548EIGEN_STRONG_INLINE Packet4s pcmp_lt<Packet4s>(const Packet4s& a, const Packet4s& b) {
1549 return vreinterpret_s16_u16(vclt_s16(a, b));
1550}
1551template <>
1552EIGEN_STRONG_INLINE Packet8s pcmp_lt<Packet8s>(const Packet8s& a, const Packet8s& b) {
1553 return vreinterpretq_s16_u16(vcltq_s16(a, b));
1554}
1555template <>
1556EIGEN_STRONG_INLINE Packet4us pcmp_lt<Packet4us>(const Packet4us& a, const Packet4us& b) {
1557 return vclt_u16(a, b);
1558}
1559template <>
1560EIGEN_STRONG_INLINE Packet8us pcmp_lt<Packet8us>(const Packet8us& a, const Packet8us& b) {
1561 return vcltq_u16(a, b);
1562}
1563template <>
1564EIGEN_STRONG_INLINE Packet2i pcmp_lt<Packet2i>(const Packet2i& a, const Packet2i& b) {
1565 return vreinterpret_s32_u32(vclt_s32(a, b));
1566}
1567template <>
1568EIGEN_STRONG_INLINE Packet4i pcmp_lt<Packet4i>(const Packet4i& a, const Packet4i& b) {
1569 return vreinterpretq_s32_u32(vcltq_s32(a, b));
1570}
1571template <>
1572EIGEN_STRONG_INLINE Packet2ui pcmp_lt<Packet2ui>(const Packet2ui& a, const Packet2ui& b) {
1573 return vclt_u32(a, b);
1574}
1575template <>
1576EIGEN_STRONG_INLINE Packet4ui pcmp_lt<Packet4ui>(const Packet4ui& a, const Packet4ui& b) {
1577 return vcltq_u32(a, b);
1578}
1579
1580template <>
1581EIGEN_STRONG_INLINE Packet2l pcmp_lt<Packet2l>(const Packet2l& a, const Packet2l& b) {
1582#if EIGEN_ARCH_ARM64
1583 return vreinterpretq_s64_u64(vcltq_s64(a, b));
1584#else
1585 return vshrq_n_s64(vqsubq_s64(a, b), 63);
1586#endif
1587}
1588template <>
1589EIGEN_STRONG_INLINE Packet2ul pcmp_lt<Packet2ul>(const Packet2ul& a, const Packet2ul& b) {
1590#if EIGEN_ARCH_ARM64
1591 return vcltq_u64(a, b);
1592#else
1593 const uint64x2_t flag = vshrq_n_u64(vreinterpretq_u64_u8(vdupq_n_u8(0xFF)), 1);
1594 return vreinterpretq_u64_s64(vshrq_n_s64(vreinterpretq_s64_u64(vqaddq_u64(vqsubq_u64(b, a), flag)), 63));
1595#endif
1596}
1597template <>
1598EIGEN_STRONG_INLINE Packet2l pcmp_le<Packet2l>(const Packet2l& a, const Packet2l& b) {
1599#if EIGEN_ARCH_ARM64
1600 return vreinterpretq_s64_u64(vcleq_s64(a, b));
1601#else
1602 return vreinterpretq_s64_u8(vmvnq_u8(vreinterpretq_u8_s64(pcmp_lt(b, a))));
1603#endif
1604}
1605template <>
1606EIGEN_STRONG_INLINE Packet2ul pcmp_le<Packet2ul>(const Packet2ul& a, const Packet2ul& b) {
1607#if EIGEN_ARCH_ARM64
1608 return vcleq_u64(a, b);
1609#else
1610 return vreinterpretq_u64_u8(vmvnq_u8(vreinterpretq_u8_u64(pcmp_lt(b, a))));
1611#endif
1612}
1613
1614template <>
1615EIGEN_STRONG_INLINE Packet2l pmin<Packet2l>(const Packet2l& a, const Packet2l& b) {
1616 return vbslq_s64(vreinterpretq_u64_s64(pcmp_lt(a, b)), a, b);
1617}
1618template <>
1619EIGEN_STRONG_INLINE Packet2l pmax<Packet2l>(const Packet2l& a, const Packet2l& b) {
1620 return vbslq_s64(vreinterpretq_u64_s64(pcmp_lt(b, a)), a, b);
1621}
1622
1623template <>
1624EIGEN_STRONG_INLINE Packet2f pcmp_eq<Packet2f>(const Packet2f& a, const Packet2f& b) {
1625 return vreinterpret_f32_u32(vceq_f32(a, b));
1626}
1627template <>
1628EIGEN_STRONG_INLINE Packet4f pcmp_eq<Packet4f>(const Packet4f& a, const Packet4f& b) {
1629 return vreinterpretq_f32_u32(vceqq_f32(a, b));
1630}
1631template <>
1632EIGEN_STRONG_INLINE Packet4c pcmp_eq<Packet4c>(const Packet4c& a, const Packet4c& b) {
1633 return vget_lane_s32(
1634 vreinterpret_s32_u8(vceq_s8(vreinterpret_s8_s32(vdup_n_s32(a)), vreinterpret_s8_s32(vdup_n_s32(b)))), 0);
1635}
1636template <>
1637EIGEN_STRONG_INLINE Packet8c pcmp_eq<Packet8c>(const Packet8c& a, const Packet8c& b) {
1638 return vreinterpret_s8_u8(vceq_s8(a, b));
1639}
1640template <>
1641EIGEN_STRONG_INLINE Packet16c pcmp_eq<Packet16c>(const Packet16c& a, const Packet16c& b) {
1642 return vreinterpretq_s8_u8(vceqq_s8(a, b));
1643}
1644template <>
1645EIGEN_STRONG_INLINE Packet4uc pcmp_eq<Packet4uc>(const Packet4uc& a, const Packet4uc& b) {
1646 return vget_lane_u32(
1647 vreinterpret_u32_u8(vceq_u8(vreinterpret_u8_u32(vdup_n_u32(a)), vreinterpret_u8_u32(vdup_n_u32(b)))), 0);
1648}
1649template <>
1650EIGEN_STRONG_INLINE Packet8uc pcmp_eq<Packet8uc>(const Packet8uc& a, const Packet8uc& b) {
1651 return vceq_u8(a, b);
1652}
1653template <>
1654EIGEN_STRONG_INLINE Packet16uc pcmp_eq<Packet16uc>(const Packet16uc& a, const Packet16uc& b) {
1655 return vceqq_u8(a, b);
1656}
1657template <>
1658EIGEN_STRONG_INLINE Packet4s pcmp_eq<Packet4s>(const Packet4s& a, const Packet4s& b) {
1659 return vreinterpret_s16_u16(vceq_s16(a, b));
1660}
1661template <>
1662EIGEN_STRONG_INLINE Packet8s pcmp_eq<Packet8s>(const Packet8s& a, const Packet8s& b) {
1663 return vreinterpretq_s16_u16(vceqq_s16(a, b));
1664}
1665template <>
1666EIGEN_STRONG_INLINE Packet4us pcmp_eq<Packet4us>(const Packet4us& a, const Packet4us& b) {
1667 return vceq_u16(a, b);
1668}
1669template <>
1670EIGEN_STRONG_INLINE Packet8us pcmp_eq<Packet8us>(const Packet8us& a, const Packet8us& b) {
1671 return vceqq_u16(a, b);
1672}
1673template <>
1674EIGEN_STRONG_INLINE Packet2i pcmp_eq<Packet2i>(const Packet2i& a, const Packet2i& b) {
1675 return vreinterpret_s32_u32(vceq_s32(a, b));
1676}
1677template <>
1678EIGEN_STRONG_INLINE Packet4i pcmp_eq<Packet4i>(const Packet4i& a, const Packet4i& b) {
1679 return vreinterpretq_s32_u32(vceqq_s32(a, b));
1680}
1681template <>
1682EIGEN_STRONG_INLINE Packet2ui pcmp_eq<Packet2ui>(const Packet2ui& a, const Packet2ui& b) {
1683 return vceq_u32(a, b);
1684}
1685template <>
1686EIGEN_STRONG_INLINE Packet4ui pcmp_eq<Packet4ui>(const Packet4ui& a, const Packet4ui& b) {
1687 return vceqq_u32(a, b);
1688}
1689template <>
1690EIGEN_STRONG_INLINE Packet2ul pcmp_eq<Packet2ul>(const Packet2ul& a, const Packet2ul& b) {
1691#if EIGEN_ARCH_ARM64
1692 return vceqq_u64(a, b);
1693#else
1694 const uint32x4_t eq = vceqq_u32(vreinterpretq_u32_u64(a), vreinterpretq_u32_u64(b));
1695 return vreinterpretq_u64_u32(vandq_u32(eq, vrev64q_u32(eq)));
1696#endif
1697}
1698template <>
1699EIGEN_STRONG_INLINE Packet2l pcmp_eq<Packet2l>(const Packet2l& a, const Packet2l& b) {
1700#if EIGEN_ARCH_ARM64
1701 return vreinterpretq_s64_u64(vceqq_s64(a, b));
1702#else
1703 return vreinterpretq_s64_u64(pcmp_eq(vreinterpretq_u64_s64(a), vreinterpretq_u64_s64(b)));
1704#endif
1705}
1706
1707template <>
1708EIGEN_STRONG_INLINE Packet2f pcmp_lt_or_nan<Packet2f>(const Packet2f& a, const Packet2f& b) {
1709 return vreinterpret_f32_u32(vmvn_u32(neon_vcge_f32(a, b)));
1710}
1711template <>
1712EIGEN_STRONG_INLINE Packet4f pcmp_lt_or_nan<Packet4f>(const Packet4f& a, const Packet4f& b) {
1713 return vreinterpretq_f32_u32(vmvnq_u32(neon_vcgeq_f32(a, b)));
1714}
1715
1716// Classify with absolute comparisons against infinity: |a| >= inf holds only for +-inf, inf > |a| only for finite
1717// values, and |a| <= inf fails only for NaN. Each is one instruction (FACGE/FACGT, VACGE/VACGT), is unaffected by
1718// flushing subnormal inputs, and avoids the self-comparison a != a, which Clang rewrites into two comparisons.
1719template <>
1720EIGEN_STRONG_INLINE Packet2f pisinf<Packet2f>(const Packet2f& a) {
1721 return vreinterpret_f32_u32(vcage_f32(a, pinf<Packet2f>()));
1722}
1723template <>
1724EIGEN_STRONG_INLINE Packet4f pisinf<Packet4f>(const Packet4f& a) {
1725 return vreinterpretq_f32_u32(vcageq_f32(a, pinf<Packet4f>()));
1726}
1727template <>
1728EIGEN_STRONG_INLINE Packet2f pisfinite<Packet2f>(const Packet2f& a) {
1729 return vreinterpret_f32_u32(vcagt_f32(pinf<Packet2f>(), a));
1730}
1731template <>
1732EIGEN_STRONG_INLINE Packet4f pisfinite<Packet4f>(const Packet4f& a) {
1733 return vreinterpretq_f32_u32(vcagtq_f32(pinf<Packet4f>(), a));
1734}
1735template <>
1736EIGEN_STRONG_INLINE Packet2f pisnan<Packet2f>(const Packet2f& a) {
1737 return vreinterpret_f32_u32(vmvn_u32(vcage_f32(pinf<Packet2f>(), a)));
1738}
1739template <>
1740EIGEN_STRONG_INLINE Packet4f pisnan<Packet4f>(const Packet4f& a) {
1741 return vreinterpretq_f32_u32(vmvnq_u32(vcageq_f32(pinf<Packet4f>(), a)));
1742}
1743
1744// Logical Operations are not supported for float, so we have to reinterpret casts using NEON intrinsics
1745template <>
1746EIGEN_STRONG_INLINE Packet2f pand<Packet2f>(const Packet2f& a, const Packet2f& b) {
1747 return vreinterpret_f32_u32(vand_u32(vreinterpret_u32_f32(a), vreinterpret_u32_f32(b)));
1748}
1749template <>
1750EIGEN_STRONG_INLINE Packet4f pand<Packet4f>(const Packet4f& a, const Packet4f& b) {
1751 return vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(a), vreinterpretq_u32_f32(b)));
1752}
1753template <>
1754EIGEN_STRONG_INLINE Packet4c pand<Packet4c>(const Packet4c& a, const Packet4c& b) {
1755 return a & b;
1756}
1757template <>
1758EIGEN_STRONG_INLINE Packet8c pand<Packet8c>(const Packet8c& a, const Packet8c& b) {
1759 return vand_s8(a, b);
1760}
1761template <>
1762EIGEN_STRONG_INLINE Packet16c pand<Packet16c>(const Packet16c& a, const Packet16c& b) {
1763 return vandq_s8(a, b);
1764}
1765template <>
1766EIGEN_STRONG_INLINE Packet4uc pand<Packet4uc>(const Packet4uc& a, const Packet4uc& b) {
1767 return a & b;
1768}
1769template <>
1770EIGEN_STRONG_INLINE Packet8uc pand<Packet8uc>(const Packet8uc& a, const Packet8uc& b) {
1771 return vand_u8(a, b);
1772}
1773template <>
1774EIGEN_STRONG_INLINE Packet16uc pand<Packet16uc>(const Packet16uc& a, const Packet16uc& b) {
1775 return vandq_u8(a, b);
1776}
1777template <>
1778EIGEN_STRONG_INLINE Packet4s pand<Packet4s>(const Packet4s& a, const Packet4s& b) {
1779 return vand_s16(a, b);
1780}
1781template <>
1782EIGEN_STRONG_INLINE Packet8s pand<Packet8s>(const Packet8s& a, const Packet8s& b) {
1783 return vandq_s16(a, b);
1784}
1785template <>
1786EIGEN_STRONG_INLINE Packet4us pand<Packet4us>(const Packet4us& a, const Packet4us& b) {
1787 return vand_u16(a, b);
1788}
1789template <>
1790EIGEN_STRONG_INLINE Packet8us pand<Packet8us>(const Packet8us& a, const Packet8us& b) {
1791 return vandq_u16(a, b);
1792}
1793template <>
1794EIGEN_STRONG_INLINE Packet2i pand<Packet2i>(const Packet2i& a, const Packet2i& b) {
1795 return vand_s32(a, b);
1796}
1797template <>
1798EIGEN_STRONG_INLINE Packet4i pand<Packet4i>(const Packet4i& a, const Packet4i& b) {
1799 return vandq_s32(a, b);
1800}
1801template <>
1802EIGEN_STRONG_INLINE Packet2ui pand<Packet2ui>(const Packet2ui& a, const Packet2ui& b) {
1803 return vand_u32(a, b);
1804}
1805template <>
1806EIGEN_STRONG_INLINE Packet4ui pand<Packet4ui>(const Packet4ui& a, const Packet4ui& b) {
1807 return vandq_u32(a, b);
1808}
1809template <>
1810EIGEN_STRONG_INLINE Packet2l pand<Packet2l>(const Packet2l& a, const Packet2l& b) {
1811 return vandq_s64(a, b);
1812}
1813template <>
1814EIGEN_STRONG_INLINE Packet2ul pand<Packet2ul>(const Packet2ul& a, const Packet2ul& b) {
1815 return vandq_u64(a, b);
1816}
1817
1818template <>
1819EIGEN_STRONG_INLINE Packet2f por<Packet2f>(const Packet2f& a, const Packet2f& b) {
1820 return vreinterpret_f32_u32(vorr_u32(vreinterpret_u32_f32(a), vreinterpret_u32_f32(b)));
1821}
1822template <>
1823EIGEN_STRONG_INLINE Packet4f por<Packet4f>(const Packet4f& a, const Packet4f& b) {
1824 return vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(a), vreinterpretq_u32_f32(b)));
1825}
1826template <>
1827EIGEN_STRONG_INLINE Packet4c por<Packet4c>(const Packet4c& a, const Packet4c& b) {
1828 return a | b;
1829}
1830template <>
1831EIGEN_STRONG_INLINE Packet8c por<Packet8c>(const Packet8c& a, const Packet8c& b) {
1832 return vorr_s8(a, b);
1833}
1834template <>
1835EIGEN_STRONG_INLINE Packet16c por<Packet16c>(const Packet16c& a, const Packet16c& b) {
1836 return vorrq_s8(a, b);
1837}
1838template <>
1839EIGEN_STRONG_INLINE Packet4uc por<Packet4uc>(const Packet4uc& a, const Packet4uc& b) {
1840 return a | b;
1841}
1842template <>
1843EIGEN_STRONG_INLINE Packet8uc por<Packet8uc>(const Packet8uc& a, const Packet8uc& b) {
1844 return vorr_u8(a, b);
1845}
1846template <>
1847EIGEN_STRONG_INLINE Packet16uc por<Packet16uc>(const Packet16uc& a, const Packet16uc& b) {
1848 return vorrq_u8(a, b);
1849}
1850template <>
1851EIGEN_STRONG_INLINE Packet4s por<Packet4s>(const Packet4s& a, const Packet4s& b) {
1852 return vorr_s16(a, b);
1853}
1854template <>
1855EIGEN_STRONG_INLINE Packet8s por<Packet8s>(const Packet8s& a, const Packet8s& b) {
1856 return vorrq_s16(a, b);
1857}
1858template <>
1859EIGEN_STRONG_INLINE Packet4us por<Packet4us>(const Packet4us& a, const Packet4us& b) {
1860 return vorr_u16(a, b);
1861}
1862template <>
1863EIGEN_STRONG_INLINE Packet8us por<Packet8us>(const Packet8us& a, const Packet8us& b) {
1864 return vorrq_u16(a, b);
1865}
1866template <>
1867EIGEN_STRONG_INLINE Packet2i por<Packet2i>(const Packet2i& a, const Packet2i& b) {
1868 return vorr_s32(a, b);
1869}
1870template <>
1871EIGEN_STRONG_INLINE Packet4i por<Packet4i>(const Packet4i& a, const Packet4i& b) {
1872 return vorrq_s32(a, b);
1873}
1874template <>
1875EIGEN_STRONG_INLINE Packet2ui por<Packet2ui>(const Packet2ui& a, const Packet2ui& b) {
1876 return vorr_u32(a, b);
1877}
1878template <>
1879EIGEN_STRONG_INLINE Packet4ui por<Packet4ui>(const Packet4ui& a, const Packet4ui& b) {
1880 return vorrq_u32(a, b);
1881}
1882template <>
1883EIGEN_STRONG_INLINE Packet2l por<Packet2l>(const Packet2l& a, const Packet2l& b) {
1884 return vorrq_s64(a, b);
1885}
1886template <>
1887EIGEN_STRONG_INLINE Packet2ul por<Packet2ul>(const Packet2ul& a, const Packet2ul& b) {
1888 return vorrq_u64(a, b);
1889}
1890
1891template <>
1892EIGEN_STRONG_INLINE Packet2f pxor<Packet2f>(const Packet2f& a, const Packet2f& b) {
1893 return vreinterpret_f32_u32(veor_u32(vreinterpret_u32_f32(a), vreinterpret_u32_f32(b)));
1894}
1895template <>
1896EIGEN_STRONG_INLINE Packet4f pxor<Packet4f>(const Packet4f& a, const Packet4f& b) {
1897 return vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(a), vreinterpretq_u32_f32(b)));
1898}
1899template <>
1900EIGEN_STRONG_INLINE Packet4c pxor<Packet4c>(const Packet4c& a, const Packet4c& b) {
1901 return a ^ b;
1902}
1903template <>
1904EIGEN_STRONG_INLINE Packet8c pxor<Packet8c>(const Packet8c& a, const Packet8c& b) {
1905 return veor_s8(a, b);
1906}
1907template <>
1908EIGEN_STRONG_INLINE Packet16c pxor<Packet16c>(const Packet16c& a, const Packet16c& b) {
1909 return veorq_s8(a, b);
1910}
1911template <>
1912EIGEN_STRONG_INLINE Packet4uc pxor<Packet4uc>(const Packet4uc& a, const Packet4uc& b) {
1913 return a ^ b;
1914}
1915template <>
1916EIGEN_STRONG_INLINE Packet8uc pxor<Packet8uc>(const Packet8uc& a, const Packet8uc& b) {
1917 return veor_u8(a, b);
1918}
1919template <>
1920EIGEN_STRONG_INLINE Packet16uc pxor<Packet16uc>(const Packet16uc& a, const Packet16uc& b) {
1921 return veorq_u8(a, b);
1922}
1923template <>
1924EIGEN_STRONG_INLINE Packet4s pxor<Packet4s>(const Packet4s& a, const Packet4s& b) {
1925 return veor_s16(a, b);
1926}
1927template <>
1928EIGEN_STRONG_INLINE Packet8s pxor<Packet8s>(const Packet8s& a, const Packet8s& b) {
1929 return veorq_s16(a, b);
1930}
1931template <>
1932EIGEN_STRONG_INLINE Packet4us pxor<Packet4us>(const Packet4us& a, const Packet4us& b) {
1933 return veor_u16(a, b);
1934}
1935template <>
1936EIGEN_STRONG_INLINE Packet8us pxor<Packet8us>(const Packet8us& a, const Packet8us& b) {
1937 return veorq_u16(a, b);
1938}
1939template <>
1940EIGEN_STRONG_INLINE Packet2i pxor<Packet2i>(const Packet2i& a, const Packet2i& b) {
1941 return veor_s32(a, b);
1942}
1943template <>
1944EIGEN_STRONG_INLINE Packet4i pxor<Packet4i>(const Packet4i& a, const Packet4i& b) {
1945 return veorq_s32(a, b);
1946}
1947template <>
1948EIGEN_STRONG_INLINE Packet2ui pxor<Packet2ui>(const Packet2ui& a, const Packet2ui& b) {
1949 return veor_u32(a, b);
1950}
1951template <>
1952EIGEN_STRONG_INLINE Packet4ui pxor<Packet4ui>(const Packet4ui& a, const Packet4ui& b) {
1953 return veorq_u32(a, b);
1954}
1955template <>
1956EIGEN_STRONG_INLINE Packet2l pxor<Packet2l>(const Packet2l& a, const Packet2l& b) {
1957 return veorq_s64(a, b);
1958}
1959template <>
1960EIGEN_STRONG_INLINE Packet2ul pxor<Packet2ul>(const Packet2ul& a, const Packet2ul& b) {
1961 return veorq_u64(a, b);
1962}
1963
1964template <>
1965EIGEN_STRONG_INLINE Packet2f pandnot<Packet2f>(const Packet2f& a, const Packet2f& b) {
1966 return vreinterpret_f32_u32(vbic_u32(vreinterpret_u32_f32(a), vreinterpret_u32_f32(b)));
1967}
1968template <>
1969EIGEN_STRONG_INLINE Packet4f pandnot<Packet4f>(const Packet4f& a, const Packet4f& b) {
1970 return vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(a), vreinterpretq_u32_f32(b)));
1971}
1972template <>
1973EIGEN_STRONG_INLINE Packet4c pandnot<Packet4c>(const Packet4c& a, const Packet4c& b) {
1974 return a & ~b;
1975}
1976template <>
1977EIGEN_STRONG_INLINE Packet8c pandnot<Packet8c>(const Packet8c& a, const Packet8c& b) {
1978 return vbic_s8(a, b);
1979}
1980template <>
1981EIGEN_STRONG_INLINE Packet16c pandnot<Packet16c>(const Packet16c& a, const Packet16c& b) {
1982 return vbicq_s8(a, b);
1983}
1984template <>
1985EIGEN_STRONG_INLINE Packet4uc pandnot<Packet4uc>(const Packet4uc& a, const Packet4uc& b) {
1986 return a & ~b;
1987}
1988template <>
1989EIGEN_STRONG_INLINE Packet8uc pandnot<Packet8uc>(const Packet8uc& a, const Packet8uc& b) {
1990 return vbic_u8(a, b);
1991}
1992template <>
1993EIGEN_STRONG_INLINE Packet16uc pandnot<Packet16uc>(const Packet16uc& a, const Packet16uc& b) {
1994 return vbicq_u8(a, b);
1995}
1996template <>
1997EIGEN_STRONG_INLINE Packet4s pandnot<Packet4s>(const Packet4s& a, const Packet4s& b) {
1998 return vbic_s16(a, b);
1999}
2000template <>
2001EIGEN_STRONG_INLINE Packet8s pandnot<Packet8s>(const Packet8s& a, const Packet8s& b) {
2002 return vbicq_s16(a, b);
2003}
2004template <>
2005EIGEN_STRONG_INLINE Packet4us pandnot<Packet4us>(const Packet4us& a, const Packet4us& b) {
2006 return vbic_u16(a, b);
2007}
2008template <>
2009EIGEN_STRONG_INLINE Packet8us pandnot<Packet8us>(const Packet8us& a, const Packet8us& b) {
2010 return vbicq_u16(a, b);
2011}
2012template <>
2013EIGEN_STRONG_INLINE Packet2i pandnot<Packet2i>(const Packet2i& a, const Packet2i& b) {
2014 return vbic_s32(a, b);
2015}
2016template <>
2017EIGEN_STRONG_INLINE Packet4i pandnot<Packet4i>(const Packet4i& a, const Packet4i& b) {
2018 return vbicq_s32(a, b);
2019}
2020template <>
2021EIGEN_STRONG_INLINE Packet2ui pandnot<Packet2ui>(const Packet2ui& a, const Packet2ui& b) {
2022 return vbic_u32(a, b);
2023}
2024template <>
2025EIGEN_STRONG_INLINE Packet4ui pandnot<Packet4ui>(const Packet4ui& a, const Packet4ui& b) {
2026 return vbicq_u32(a, b);
2027}
2028template <>
2029EIGEN_STRONG_INLINE Packet2l pandnot<Packet2l>(const Packet2l& a, const Packet2l& b) {
2030 return vbicq_s64(a, b);
2031}
2032template <>
2033EIGEN_STRONG_INLINE Packet2ul pandnot<Packet2ul>(const Packet2ul& a, const Packet2ul& b) {
2034 return vbicq_u64(a, b);
2035}
2036
2037template <int N>
2038EIGEN_STRONG_INLINE Packet4c parithmetic_shift_right(const Packet4c& a) {
2039 return vget_lane_s32(vreinterpret_s32_s8(vshr_n_s8(vreinterpret_s8_s32(vdup_n_s32(a)), N)), 0);
2040}
2041template <int N>
2042EIGEN_STRONG_INLINE Packet8c parithmetic_shift_right(const Packet8c& a) {
2043 return vshr_n_s8(a, N);
2044}
2045template <int N>
2046EIGEN_STRONG_INLINE Packet16c parithmetic_shift_right(const Packet16c& a) {
2047 return vshrq_n_s8(a, N);
2048}
2049template <int N>
2050EIGEN_STRONG_INLINE Packet4uc parithmetic_shift_right(const Packet4uc& a) {
2051 return vget_lane_u32(vreinterpret_u32_u8(vshr_n_u8(vreinterpret_u8_u32(vdup_n_u32(a)), N)), 0);
2052}
2053template <int N>
2054EIGEN_STRONG_INLINE Packet8uc parithmetic_shift_right(const Packet8uc& a) {
2055 return vshr_n_u8(a, N);
2056}
2057template <int N>
2058EIGEN_STRONG_INLINE Packet16uc parithmetic_shift_right(const Packet16uc& a) {
2059 return vshrq_n_u8(a, N);
2060}
2061template <int N>
2062EIGEN_STRONG_INLINE Packet4s parithmetic_shift_right(const Packet4s& a) {
2063 return vshr_n_s16(a, N);
2064}
2065template <int N>
2066EIGEN_STRONG_INLINE Packet8s parithmetic_shift_right(const Packet8s& a) {
2067 return vshrq_n_s16(a, N);
2068}
2069template <int N>
2070EIGEN_STRONG_INLINE Packet4us parithmetic_shift_right(const Packet4us& a) {
2071 return vshr_n_u16(a, N);
2072}
2073template <int N>
2074EIGEN_STRONG_INLINE Packet8us parithmetic_shift_right(const Packet8us& a) {
2075 return vshrq_n_u16(a, N);
2076}
2077template <int N>
2078EIGEN_STRONG_INLINE Packet2i parithmetic_shift_right(const Packet2i& a) {
2079 return vshr_n_s32(a, N);
2080}
2081template <int N>
2082EIGEN_STRONG_INLINE Packet4i parithmetic_shift_right(const Packet4i& a) {
2083 return vshrq_n_s32(a, N);
2084}
2085template <int N>
2086EIGEN_STRONG_INLINE Packet2ui parithmetic_shift_right(const Packet2ui& a) {
2087 return vshr_n_u32(a, N);
2088}
2089template <int N>
2090EIGEN_STRONG_INLINE Packet4ui parithmetic_shift_right(const Packet4ui& a) {
2091 return vshrq_n_u32(a, N);
2092}
2093template <int N>
2094EIGEN_STRONG_INLINE Packet2l parithmetic_shift_right(const Packet2l& a) {
2095 return vshrq_n_s64(a, N);
2096}
2097template <int N>
2098EIGEN_STRONG_INLINE Packet2ul parithmetic_shift_right(const Packet2ul& a) {
2099 return vshrq_n_u64(a, N);
2100}
2101
2102template <int N>
2103EIGEN_STRONG_INLINE Packet4c plogical_shift_right(const Packet4c& a) {
2104 return vget_lane_s32(vreinterpret_s32_u8(vshr_n_u8(vreinterpret_u8_s32(vdup_n_s32(a)), N)), 0);
2105}
2106template <int N>
2107EIGEN_STRONG_INLINE Packet8c plogical_shift_right(const Packet8c& a) {
2108 return vreinterpret_s8_u8(vshr_n_u8(vreinterpret_u8_s8(a), N));
2109}
2110template <int N>
2111EIGEN_STRONG_INLINE Packet16c plogical_shift_right(const Packet16c& a) {
2112 return vreinterpretq_s8_u8(vshrq_n_u8(vreinterpretq_u8_s8(a), N));
2113}
2114template <int N>
2115EIGEN_STRONG_INLINE Packet4uc plogical_shift_right(const Packet4uc& a) {
2116 return vget_lane_u32(vreinterpret_u32_u8(vshr_n_u8(vreinterpret_u8_u32(vdup_n_u32(a)), N)), 0);
2117}
2118template <int N>
2119EIGEN_STRONG_INLINE Packet8uc plogical_shift_right(const Packet8uc& a) {
2120 return vshr_n_u8(a, N);
2121}
2122template <int N>
2123EIGEN_STRONG_INLINE Packet16uc plogical_shift_right(const Packet16uc& a) {
2124 return vshrq_n_u8(a, N);
2125}
2126template <int N>
2127EIGEN_STRONG_INLINE Packet4s plogical_shift_right(const Packet4s& a) {
2128 return vreinterpret_s16_u16(vshr_n_u16(vreinterpret_u16_s16(a), N));
2129}
2130template <int N>
2131EIGEN_STRONG_INLINE Packet8s plogical_shift_right(const Packet8s& a) {
2132 return vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(a), N));
2133}
2134template <int N>
2135EIGEN_STRONG_INLINE Packet4us plogical_shift_right(const Packet4us& a) {
2136 return vshr_n_u16(a, N);
2137}
2138template <int N>
2139EIGEN_STRONG_INLINE Packet8us plogical_shift_right(const Packet8us& a) {
2140 return vshrq_n_u16(a, N);
2141}
2142template <int N>
2143EIGEN_STRONG_INLINE Packet2i plogical_shift_right(const Packet2i& a) {
2144 return vreinterpret_s32_u32(vshr_n_u32(vreinterpret_u32_s32(a), N));
2145}
2146template <int N>
2147EIGEN_STRONG_INLINE Packet4i plogical_shift_right(const Packet4i& a) {
2148 return vreinterpretq_s32_u32(vshrq_n_u32(vreinterpretq_u32_s32(a), N));
2149}
2150template <int N>
2151EIGEN_STRONG_INLINE Packet2ui plogical_shift_right(const Packet2ui& a) {
2152 return vshr_n_u32(a, N);
2153}
2154template <int N>
2155EIGEN_STRONG_INLINE Packet4ui plogical_shift_right(const Packet4ui& a) {
2156 return vshrq_n_u32(a, N);
2157}
2158template <int N>
2159EIGEN_STRONG_INLINE Packet2l plogical_shift_right(const Packet2l& a) {
2160 return vreinterpretq_s64_u64(vshrq_n_u64(vreinterpretq_u64_s64(a), N));
2161}
2162template <int N>
2163EIGEN_STRONG_INLINE Packet2ul plogical_shift_right(const Packet2ul& a) {
2164 return vshrq_n_u64(a, N);
2165}
2166
2167template <int N>
2168EIGEN_STRONG_INLINE Packet4c plogical_shift_left(const Packet4c& a) {
2169 return vget_lane_s32(vreinterpret_s32_s8(vshl_n_s8(vreinterpret_s8_s32(vdup_n_s32(a)), N)), 0);
2170}
2171template <int N>
2172EIGEN_STRONG_INLINE Packet8c plogical_shift_left(const Packet8c& a) {
2173 return vshl_n_s8(a, N);
2174}
2175template <int N>
2176EIGEN_STRONG_INLINE Packet16c plogical_shift_left(const Packet16c& a) {
2177 return vshlq_n_s8(a, N);
2178}
2179template <int N>
2180EIGEN_STRONG_INLINE Packet4uc plogical_shift_left(const Packet4uc& a) {
2181 return vget_lane_u32(vreinterpret_u32_u8(vshl_n_u8(vreinterpret_u8_u32(vdup_n_u32(a)), N)), 0);
2182}
2183template <int N>
2184EIGEN_STRONG_INLINE Packet8uc plogical_shift_left(const Packet8uc& a) {
2185 return vshl_n_u8(a, N);
2186}
2187template <int N>
2188EIGEN_STRONG_INLINE Packet16uc plogical_shift_left(const Packet16uc& a) {
2189 return vshlq_n_u8(a, N);
2190}
2191template <int N>
2192EIGEN_STRONG_INLINE Packet4s plogical_shift_left(const Packet4s& a) {
2193 return vshl_n_s16(a, N);
2194}
2195template <int N>
2196EIGEN_STRONG_INLINE Packet8s plogical_shift_left(const Packet8s& a) {
2197 return vshlq_n_s16(a, N);
2198}
2199template <int N>
2200EIGEN_STRONG_INLINE Packet4us plogical_shift_left(const Packet4us& a) {
2201 return vshl_n_u16(a, N);
2202}
2203template <int N>
2204EIGEN_STRONG_INLINE Packet8us plogical_shift_left(const Packet8us& a) {
2205 return vshlq_n_u16(a, N);
2206}
2207template <int N>
2208EIGEN_STRONG_INLINE Packet2i plogical_shift_left(const Packet2i& a) {
2209 return vshl_n_s32(a, N);
2210}
2211template <int N>
2212EIGEN_STRONG_INLINE Packet4i plogical_shift_left(const Packet4i& a) {
2213 return vshlq_n_s32(a, N);
2214}
2215template <int N>
2216EIGEN_STRONG_INLINE Packet2ui plogical_shift_left(const Packet2ui& a) {
2217 return vshl_n_u32(a, N);
2218}
2219template <int N>
2220EIGEN_STRONG_INLINE Packet4ui plogical_shift_left(const Packet4ui& a) {
2221 return vshlq_n_u32(a, N);
2222}
2223template <int N>
2224EIGEN_STRONG_INLINE Packet2l plogical_shift_left(const Packet2l& a) {
2225 return vshlq_n_s64(a, N);
2226}
2227template <int N>
2228EIGEN_STRONG_INLINE Packet2ul plogical_shift_left(const Packet2ul& a) {
2229 return vshlq_n_u64(a, N);
2230}
2231
2232template <>
2233EIGEN_STRONG_INLINE Packet2f pload<Packet2f>(const float* from) {
2234 EIGEN_DEBUG_ALIGNED_LOAD return vld1_f32(assume_aligned<unpacket_traits<Packet2f>::alignment>(from));
2235}
2236template <>
2237EIGEN_STRONG_INLINE Packet4f pload<Packet4f>(const float* from) {
2238 EIGEN_DEBUG_ALIGNED_LOAD return vld1q_f32(assume_aligned<unpacket_traits<Packet4f>::alignment>(from));
2239}
2240template <>
2241EIGEN_STRONG_INLINE Packet4c pload<Packet4c>(const int8_t* from) {
2242 Packet4c res;
2243 memcpy(&res, from, sizeof(Packet4c));
2244 return res;
2245}
2246template <>
2247EIGEN_STRONG_INLINE Packet8c pload<Packet8c>(const int8_t* from) {
2248 EIGEN_DEBUG_ALIGNED_LOAD return vld1_s8(assume_aligned<unpacket_traits<Packet8c>::alignment>(from));
2249}
2250template <>
2251EIGEN_STRONG_INLINE Packet16c pload<Packet16c>(const int8_t* from) {
2252 EIGEN_DEBUG_ALIGNED_LOAD return vld1q_s8(assume_aligned<unpacket_traits<Packet16c>::alignment>(from));
2253}
2254template <>
2255EIGEN_STRONG_INLINE Packet4uc pload<Packet4uc>(const uint8_t* from) {
2256 Packet4uc res;
2257 memcpy(&res, from, sizeof(Packet4uc));
2258 return res;
2259}
2260template <>
2261EIGEN_STRONG_INLINE Packet8uc pload<Packet8uc>(const uint8_t* from) {
2262 EIGEN_DEBUG_ALIGNED_LOAD return vld1_u8(assume_aligned<unpacket_traits<Packet8uc>::alignment>(from));
2263}
2264template <>
2265EIGEN_STRONG_INLINE Packet16uc pload<Packet16uc>(const uint8_t* from) {
2266 EIGEN_DEBUG_ALIGNED_LOAD return vld1q_u8(assume_aligned<unpacket_traits<Packet16uc>::alignment>(from));
2267}
2268template <>
2269EIGEN_STRONG_INLINE Packet4s pload<Packet4s>(const int16_t* from) {
2270 EIGEN_DEBUG_ALIGNED_LOAD return vld1_s16(assume_aligned<unpacket_traits<Packet4s>::alignment>(from));
2271}
2272template <>
2273EIGEN_STRONG_INLINE Packet8s pload<Packet8s>(const int16_t* from) {
2274 EIGEN_DEBUG_ALIGNED_LOAD return vld1q_s16(assume_aligned<unpacket_traits<Packet8s>::alignment>(from));
2275}
2276template <>
2277EIGEN_STRONG_INLINE Packet4us pload<Packet4us>(const uint16_t* from) {
2278 EIGEN_DEBUG_ALIGNED_LOAD return vld1_u16(assume_aligned<unpacket_traits<Packet4us>::alignment>(from));
2279}
2280template <>
2281EIGEN_STRONG_INLINE Packet8us pload<Packet8us>(const uint16_t* from) {
2282 EIGEN_DEBUG_ALIGNED_LOAD return vld1q_u16(assume_aligned<unpacket_traits<Packet8us>::alignment>(from));
2283}
2284template <>
2285EIGEN_STRONG_INLINE Packet2i pload<Packet2i>(const int32_t* from) {
2286 EIGEN_DEBUG_ALIGNED_LOAD return vld1_s32(assume_aligned<unpacket_traits<Packet2i>::alignment>(from));
2287}
2288template <>
2289EIGEN_STRONG_INLINE Packet4i pload<Packet4i>(const int32_t* from) {
2290 EIGEN_DEBUG_ALIGNED_LOAD return vld1q_s32(assume_aligned<unpacket_traits<Packet4i>::alignment>(from));
2291}
2292template <>
2293EIGEN_STRONG_INLINE Packet2ui pload<Packet2ui>(const uint32_t* from) {
2294 EIGEN_DEBUG_ALIGNED_LOAD return vld1_u32(assume_aligned<unpacket_traits<Packet2ui>::alignment>(from));
2295}
2296template <>
2297EIGEN_STRONG_INLINE Packet4ui pload<Packet4ui>(const uint32_t* from) {
2298 EIGEN_DEBUG_ALIGNED_LOAD return vld1q_u32(assume_aligned<unpacket_traits<Packet4ui>::alignment>(from));
2299}
2300template <>
2301EIGEN_STRONG_INLINE Packet2l pload<Packet2l>(const int64_t* from) {
2302 EIGEN_DEBUG_ALIGNED_LOAD return vld1q_s64(assume_aligned<unpacket_traits<Packet2l>::alignment>(from));
2303}
2304template <>
2305EIGEN_STRONG_INLINE Packet2ul pload<Packet2ul>(const uint64_t* from) {
2306 EIGEN_DEBUG_ALIGNED_LOAD return vld1q_u64(assume_aligned<unpacket_traits<Packet2ul>::alignment>(from));
2307}
2308
2309template <>
2310EIGEN_STRONG_INLINE Packet2f ploadu<Packet2f>(const float* from) {
2311 EIGEN_DEBUG_UNALIGNED_LOAD return vld1_f32(from);
2312}
2313template <>
2314EIGEN_STRONG_INLINE Packet4f ploadu<Packet4f>(const float* from) {
2315 EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_f32(from);
2316}
2317template <>
2318EIGEN_STRONG_INLINE Packet4c ploadu<Packet4c>(const int8_t* from) {
2319 Packet4c res;
2320 memcpy(&res, from, sizeof(Packet4c));
2321 return res;
2322}
2323template <>
2324EIGEN_STRONG_INLINE Packet8c ploadu<Packet8c>(const int8_t* from) {
2325 EIGEN_DEBUG_UNALIGNED_LOAD return vld1_s8(from);
2326}
2327template <>
2328EIGEN_STRONG_INLINE Packet16c ploadu<Packet16c>(const int8_t* from) {
2329 EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_s8(from);
2330}
2331template <>
2332EIGEN_STRONG_INLINE Packet4uc ploadu<Packet4uc>(const uint8_t* from) {
2333 Packet4uc res;
2334 memcpy(&res, from, sizeof(Packet4uc));
2335 return res;
2336}
2337template <>
2338EIGEN_STRONG_INLINE Packet8uc ploadu<Packet8uc>(const uint8_t* from) {
2339 EIGEN_DEBUG_UNALIGNED_LOAD return vld1_u8(from);
2340}
2341template <>
2342EIGEN_STRONG_INLINE Packet16uc ploadu<Packet16uc>(const uint8_t* from) {
2343 EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_u8(from);
2344}
2345template <>
2346EIGEN_STRONG_INLINE Packet4s ploadu<Packet4s>(const int16_t* from) {
2347 EIGEN_DEBUG_UNALIGNED_LOAD return vld1_s16(from);
2348}
2349template <>
2350EIGEN_STRONG_INLINE Packet8s ploadu<Packet8s>(const int16_t* from) {
2351 EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_s16(from);
2352}
2353template <>
2354EIGEN_STRONG_INLINE Packet4us ploadu<Packet4us>(const uint16_t* from) {
2355 EIGEN_DEBUG_UNALIGNED_LOAD return vld1_u16(from);
2356}
2357template <>
2358EIGEN_STRONG_INLINE Packet8us ploadu<Packet8us>(const uint16_t* from) {
2359 EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_u16(from);
2360}
2361template <>
2362EIGEN_STRONG_INLINE Packet2i ploadu<Packet2i>(const int32_t* from) {
2363 EIGEN_DEBUG_UNALIGNED_LOAD return vld1_s32(from);
2364}
2365template <>
2366EIGEN_STRONG_INLINE Packet4i ploadu<Packet4i>(const int32_t* from) {
2367 EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_s32(from);
2368}
2369template <>
2370EIGEN_STRONG_INLINE Packet2ui ploadu<Packet2ui>(const uint32_t* from) {
2371 EIGEN_DEBUG_UNALIGNED_LOAD return vld1_u32(from);
2372}
2373template <>
2374EIGEN_STRONG_INLINE Packet4ui ploadu<Packet4ui>(const uint32_t* from) {
2375 EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_u32(from);
2376}
2377template <>
2378EIGEN_STRONG_INLINE Packet2l ploadu<Packet2l>(const int64_t* from) {
2379 EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_s64(from);
2380}
2381template <>
2382EIGEN_STRONG_INLINE Packet2ul ploadu<Packet2ul>(const uint64_t* from) {
2383 EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_u64(from);
2384}
2385
2386template <>
2387EIGEN_STRONG_INLINE Packet2f ploaddup<Packet2f>(const float* from) {
2388 return vld1_dup_f32(from);
2389}
2390template <>
2391EIGEN_STRONG_INLINE Packet4f ploaddup<Packet4f>(const float* from) {
2392 return vcombine_f32(vld1_dup_f32(from), vld1_dup_f32(from + 1));
2393}
2394template <>
2395EIGEN_STRONG_INLINE Packet4c ploaddup<Packet4c>(const int8_t* from) {
2396 const int8x8_t a = vreinterpret_s8_s32(vdup_n_s32(pload<Packet4c>(from)));
2397 return vget_lane_s32(vreinterpret_s32_s8(vzip_s8(a, a).val[0]), 0);
2398}
2399template <>
2400EIGEN_STRONG_INLINE Packet8c ploaddup<Packet8c>(const int8_t* from) {
2401 const int8x8_t a = vld1_s8(from);
2402 return vzip_s8(a, a).val[0];
2403}
2404template <>
2405EIGEN_STRONG_INLINE Packet16c ploaddup<Packet16c>(const int8_t* from) {
2406 const int8x8_t a = vld1_s8(from);
2407 const int8x8x2_t b = vzip_s8(a, a);
2408 return vcombine_s8(b.val[0], b.val[1]);
2409}
2410template <>
2411EIGEN_STRONG_INLINE Packet4uc ploaddup<Packet4uc>(const uint8_t* from) {
2412 const uint8x8_t a = vreinterpret_u8_u32(vdup_n_u32(pload<Packet4uc>(from)));
2413 return vget_lane_u32(vreinterpret_u32_u8(vzip_u8(a, a).val[0]), 0);
2414}
2415template <>
2416EIGEN_STRONG_INLINE Packet8uc ploaddup<Packet8uc>(const uint8_t* from) {
2417 const uint8x8_t a = vld1_u8(from);
2418 return vzip_u8(a, a).val[0];
2419}
2420template <>
2421EIGEN_STRONG_INLINE Packet16uc ploaddup<Packet16uc>(const uint8_t* from) {
2422 const uint8x8_t a = vld1_u8(from);
2423 const uint8x8x2_t b = vzip_u8(a, a);
2424 return vcombine_u8(b.val[0], b.val[1]);
2425}
2426template <>
2427EIGEN_STRONG_INLINE Packet4s ploaddup<Packet4s>(const int16_t* from) {
2428 return vreinterpret_s16_u32(
2429 vzip_u32(vreinterpret_u32_s16(vld1_dup_s16(from)), vreinterpret_u32_s16(vld1_dup_s16(from + 1))).val[0]);
2430}
2431template <>
2432EIGEN_STRONG_INLINE Packet8s ploaddup<Packet8s>(const int16_t* from) {
2433 const int16x4_t a = vld1_s16(from);
2434 const int16x4x2_t b = vzip_s16(a, a);
2435 return vcombine_s16(b.val[0], b.val[1]);
2436}
2437template <>
2438EIGEN_STRONG_INLINE Packet4us ploaddup<Packet4us>(const uint16_t* from) {
2439 return vreinterpret_u16_u32(
2440 vzip_u32(vreinterpret_u32_u16(vld1_dup_u16(from)), vreinterpret_u32_u16(vld1_dup_u16(from + 1))).val[0]);
2441}
2442template <>
2443EIGEN_STRONG_INLINE Packet8us ploaddup<Packet8us>(const uint16_t* from) {
2444 const uint16x4_t a = vld1_u16(from);
2445 const uint16x4x2_t b = vzip_u16(a, a);
2446 return vcombine_u16(b.val[0], b.val[1]);
2447}
2448template <>
2449EIGEN_STRONG_INLINE Packet2i ploaddup<Packet2i>(const int32_t* from) {
2450 return vld1_dup_s32(from);
2451}
2452template <>
2453EIGEN_STRONG_INLINE Packet4i ploaddup<Packet4i>(const int32_t* from) {
2454 return vcombine_s32(vld1_dup_s32(from), vld1_dup_s32(from + 1));
2455}
2456template <>
2457EIGEN_STRONG_INLINE Packet2ui ploaddup<Packet2ui>(const uint32_t* from) {
2458 return vld1_dup_u32(from);
2459}
2460template <>
2461EIGEN_STRONG_INLINE Packet4ui ploaddup<Packet4ui>(const uint32_t* from) {
2462 return vcombine_u32(vld1_dup_u32(from), vld1_dup_u32(from + 1));
2463}
2464template <>
2465EIGEN_STRONG_INLINE Packet2l ploaddup<Packet2l>(const int64_t* from) {
2466 return vld1q_dup_s64(from);
2467}
2468template <>
2469EIGEN_STRONG_INLINE Packet2ul ploaddup<Packet2ul>(const uint64_t* from) {
2470 return vld1q_dup_u64(from);
2471}
2472
2473template <>
2474EIGEN_STRONG_INLINE Packet4f ploadquad<Packet4f>(const float* from) {
2475 return vld1q_dup_f32(from);
2476}
2477
2478// WORKAROUND: Apple Clang 17.0.0 (and Homebrew Clang 21.1.8) at -O0 optimization
2479// generate incorrect code for vld1_dup_[su]8, ignoring the pointer offset.
2480// We use vdup_n_s8(*from) to force a safe scalar load before broadcast.
2481EIGEN_ALWAYS_INLINE int8x8_t eigen_vld1_dup_s8(const int8_t* ptr) {
2482#if EIGEN_COMP_CLANGAPPLE && EIGEN_ARCH_ARM64
2483 return vdup_n_s8(*ptr);
2484#else
2485 return vld1_dup_s8(ptr);
2486#endif
2487}
2488
2489EIGEN_ALWAYS_INLINE uint8x8_t eigen_vld1_dup_u8(const uint8_t* ptr) {
2490#if EIGEN_COMP_CLANGAPPLE && EIGEN_ARCH_ARM64
2491 return vdup_n_u8(*ptr);
2492#else
2493 return vld1_dup_u8(ptr);
2494#endif
2495}
2496
2497template <>
2498EIGEN_STRONG_INLINE Packet4c ploadquad<Packet4c>(const int8_t* from) {
2499 return vget_lane_s32(vreinterpret_s32_s8(eigen_vld1_dup_s8(from)), 0);
2500}
2501template <>
2502EIGEN_STRONG_INLINE Packet8c ploadquad<Packet8c>(const int8_t* from) {
2503 return vreinterpret_s8_u32(
2504 vzip_u32(vreinterpret_u32_s8(eigen_vld1_dup_s8(from)), vreinterpret_u32_s8(eigen_vld1_dup_s8(from + 1))).val[0]);
2505}
2506template <>
2507EIGEN_STRONG_INLINE Packet16c ploadquad<Packet16c>(const int8_t* from) {
2508 const int8x8_t a = vreinterpret_s8_u32(
2509 vzip_u32(vreinterpret_u32_s8(eigen_vld1_dup_s8(from)), vreinterpret_u32_s8(eigen_vld1_dup_s8(from + 1))).val[0]);
2510 const int8x8_t b = vreinterpret_s8_u32(
2511 vzip_u32(vreinterpret_u32_s8(eigen_vld1_dup_s8(from + 2)), vreinterpret_u32_s8(eigen_vld1_dup_s8(from + 3)))
2512 .val[0]);
2513 return vcombine_s8(a, b);
2514}
2515template <>
2516EIGEN_STRONG_INLINE Packet4uc ploadquad<Packet4uc>(const uint8_t* from) {
2517 return vget_lane_u32(vreinterpret_u32_u8(eigen_vld1_dup_u8(from)), 0);
2518}
2519template <>
2520EIGEN_STRONG_INLINE Packet8uc ploadquad<Packet8uc>(const uint8_t* from) {
2521 return vreinterpret_u8_u32(
2522 vzip_u32(vreinterpret_u32_u8(eigen_vld1_dup_u8(from)), vreinterpret_u32_u8(eigen_vld1_dup_u8(from + 1))).val[0]);
2523}
2524template <>
2525EIGEN_STRONG_INLINE Packet16uc ploadquad<Packet16uc>(const uint8_t* from) {
2526 const uint8x8_t a = vreinterpret_u8_u32(
2527 vzip_u32(vreinterpret_u32_u8(eigen_vld1_dup_u8(from)), vreinterpret_u32_u8(eigen_vld1_dup_u8(from + 1))).val[0]);
2528 const uint8x8_t b = vreinterpret_u8_u32(
2529 vzip_u32(vreinterpret_u32_u8(eigen_vld1_dup_u8(from + 2)), vreinterpret_u32_u8(eigen_vld1_dup_u8(from + 3)))
2530 .val[0]);
2531 return vcombine_u8(a, b);
2532}
2533template <>
2534EIGEN_STRONG_INLINE Packet8s ploadquad<Packet8s>(const int16_t* from) {
2535 return vcombine_s16(vld1_dup_s16(from), vld1_dup_s16(from + 1));
2536}
2537template <>
2538EIGEN_STRONG_INLINE Packet8us ploadquad<Packet8us>(const uint16_t* from) {
2539 return vcombine_u16(vld1_dup_u16(from), vld1_dup_u16(from + 1));
2540}
2541template <>
2542EIGEN_STRONG_INLINE Packet4i ploadquad<Packet4i>(const int32_t* from) {
2543 return vld1q_dup_s32(from);
2544}
2545template <>
2546EIGEN_STRONG_INLINE Packet4ui ploadquad<Packet4ui>(const uint32_t* from) {
2547 return vld1q_dup_u32(from);
2548}
2549
2550template <>
2551EIGEN_STRONG_INLINE void pstore<float>(float* to, const Packet2f& from) {
2552 EIGEN_DEBUG_ALIGNED_STORE vst1_f32(assume_aligned<unpacket_traits<Packet2f>::alignment>(to), from);
2553}
2554template <>
2555EIGEN_STRONG_INLINE void pstore<float>(float* to, const Packet4f& from) {
2556 EIGEN_DEBUG_ALIGNED_STORE vst1q_f32(assume_aligned<unpacket_traits<Packet4f>::alignment>(to), from);
2557}
2558template <>
2559EIGEN_STRONG_INLINE void pstore<int8_t>(int8_t* to, const Packet4c& from) {
2560 memcpy(to, &from, sizeof(from));
2561}
2562template <>
2563EIGEN_STRONG_INLINE void pstore<int8_t>(int8_t* to, const Packet8c& from) {
2564 EIGEN_DEBUG_ALIGNED_STORE vst1_s8(assume_aligned<unpacket_traits<Packet8c>::alignment>(to), from);
2565}
2566template <>
2567EIGEN_STRONG_INLINE void pstore<int8_t>(int8_t* to, const Packet16c& from) {
2568 EIGEN_DEBUG_ALIGNED_STORE vst1q_s8(assume_aligned<unpacket_traits<Packet16c>::alignment>(to), from);
2569}
2570template <>
2571EIGEN_STRONG_INLINE void pstore<uint8_t>(uint8_t* to, const Packet4uc& from) {
2572 memcpy(to, &from, sizeof(from));
2573}
2574template <>
2575EIGEN_STRONG_INLINE void pstore<uint8_t>(uint8_t* to, const Packet8uc& from) {
2576 EIGEN_DEBUG_ALIGNED_STORE vst1_u8(assume_aligned<unpacket_traits<Packet8uc>::alignment>(to), from);
2577}
2578template <>
2579EIGEN_STRONG_INLINE void pstore<uint8_t>(uint8_t* to, const Packet16uc& from) {
2580 EIGEN_DEBUG_ALIGNED_STORE vst1q_u8(assume_aligned<unpacket_traits<Packet16uc>::alignment>(to), from);
2581}
2582template <>
2583EIGEN_STRONG_INLINE void pstore<int16_t>(int16_t* to, const Packet4s& from) {
2584 EIGEN_DEBUG_ALIGNED_STORE vst1_s16(assume_aligned<unpacket_traits<Packet4s>::alignment>(to), from);
2585}
2586template <>
2587EIGEN_STRONG_INLINE void pstore<int16_t>(int16_t* to, const Packet8s& from) {
2588 EIGEN_DEBUG_ALIGNED_STORE vst1q_s16(assume_aligned<unpacket_traits<Packet8s>::alignment>(to), from);
2589}
2590template <>
2591EIGEN_STRONG_INLINE void pstore<uint16_t>(uint16_t* to, const Packet4us& from) {
2592 EIGEN_DEBUG_ALIGNED_STORE vst1_u16(assume_aligned<unpacket_traits<Packet4us>::alignment>(to), from);
2593}
2594template <>
2595EIGEN_STRONG_INLINE void pstore<uint16_t>(uint16_t* to, const Packet8us& from) {
2596 EIGEN_DEBUG_ALIGNED_STORE vst1q_u16(assume_aligned<unpacket_traits<Packet8us>::alignment>(to), from);
2597}
2598template <>
2599EIGEN_STRONG_INLINE void pstore<int32_t>(int32_t* to, const Packet2i& from) {
2600 EIGEN_DEBUG_ALIGNED_STORE vst1_s32(assume_aligned<unpacket_traits<Packet2i>::alignment>(to), from);
2601}
2602template <>
2603EIGEN_STRONG_INLINE void pstore<int32_t>(int32_t* to, const Packet4i& from) {
2604 EIGEN_DEBUG_ALIGNED_STORE vst1q_s32(assume_aligned<unpacket_traits<Packet4i>::alignment>(to), from);
2605}
2606template <>
2607EIGEN_STRONG_INLINE void pstore<uint32_t>(uint32_t* to, const Packet2ui& from) {
2608 EIGEN_DEBUG_ALIGNED_STORE vst1_u32(assume_aligned<unpacket_traits<Packet2ui>::alignment>(to), from);
2609}
2610template <>
2611EIGEN_STRONG_INLINE void pstore<uint32_t>(uint32_t* to, const Packet4ui& from) {
2612 EIGEN_DEBUG_ALIGNED_STORE vst1q_u32(assume_aligned<unpacket_traits<Packet4ui>::alignment>(to), from);
2613}
2614template <>
2615EIGEN_STRONG_INLINE void pstore<int64_t>(int64_t* to, const Packet2l& from) {
2616 EIGEN_DEBUG_ALIGNED_STORE vst1q_s64(assume_aligned<unpacket_traits<Packet2l>::alignment>(to), from);
2617}
2618template <>
2619EIGEN_STRONG_INLINE void pstore<uint64_t>(uint64_t* to, const Packet2ul& from) {
2620 EIGEN_DEBUG_ALIGNED_STORE vst1q_u64(assume_aligned<unpacket_traits<Packet2ul>::alignment>(to), from);
2621}
2622
2623template <>
2624EIGEN_STRONG_INLINE void pstoreu<float>(float* to, const Packet2f& from) {
2625 EIGEN_DEBUG_UNALIGNED_STORE vst1_f32(to, from);
2626}
2627template <>
2628EIGEN_STRONG_INLINE void pstoreu<float>(float* to, const Packet4f& from) {
2629 EIGEN_DEBUG_UNALIGNED_STORE vst1q_f32(to, from);
2630}
2631template <>
2632EIGEN_STRONG_INLINE void pstoreu<int8_t>(int8_t* to, const Packet4c& from) {
2633 memcpy(to, &from, sizeof(from));
2634}
2635template <>
2636EIGEN_STRONG_INLINE void pstoreu<int8_t>(int8_t* to, const Packet8c& from) {
2637 EIGEN_DEBUG_UNALIGNED_STORE vst1_s8(to, from);
2638}
2639template <>
2640EIGEN_STRONG_INLINE void pstoreu<int8_t>(int8_t* to, const Packet16c& from) {
2641 EIGEN_DEBUG_UNALIGNED_STORE vst1q_s8(to, from);
2642}
2643template <>
2644EIGEN_STRONG_INLINE void pstoreu<uint8_t>(uint8_t* to, const Packet4uc& from) {
2645 memcpy(to, &from, sizeof(from));
2646}
2647template <>
2648EIGEN_STRONG_INLINE void pstoreu<uint8_t>(uint8_t* to, const Packet8uc& from) {
2649 EIGEN_DEBUG_UNALIGNED_STORE vst1_u8(to, from);
2650}
2651template <>
2652EIGEN_STRONG_INLINE void pstoreu<uint8_t>(uint8_t* to, const Packet16uc& from) {
2653 EIGEN_DEBUG_UNALIGNED_STORE vst1q_u8(to, from);
2654}
2655template <>
2656EIGEN_STRONG_INLINE void pstoreu<int16_t>(int16_t* to, const Packet4s& from) {
2657 EIGEN_DEBUG_UNALIGNED_STORE vst1_s16(to, from);
2658}
2659template <>
2660EIGEN_STRONG_INLINE void pstoreu<int16_t>(int16_t* to, const Packet8s& from) {
2661 EIGEN_DEBUG_UNALIGNED_STORE vst1q_s16(to, from);
2662}
2663template <>
2664EIGEN_STRONG_INLINE void pstoreu<uint16_t>(uint16_t* to, const Packet4us& from) {
2665 EIGEN_DEBUG_UNALIGNED_STORE vst1_u16(to, from);
2666}
2667template <>
2668EIGEN_STRONG_INLINE void pstoreu<uint16_t>(uint16_t* to, const Packet8us& from) {
2669 EIGEN_DEBUG_UNALIGNED_STORE vst1q_u16(to, from);
2670}
2671template <>
2672EIGEN_STRONG_INLINE void pstoreu<int32_t>(int32_t* to, const Packet2i& from) {
2673 EIGEN_DEBUG_UNALIGNED_STORE vst1_s32(to, from);
2674}
2675template <>
2676EIGEN_STRONG_INLINE void pstoreu<int32_t>(int32_t* to, const Packet4i& from) {
2677 EIGEN_DEBUG_UNALIGNED_STORE vst1q_s32(to, from);
2678}
2679template <>
2680EIGEN_STRONG_INLINE void pstoreu<uint32_t>(uint32_t* to, const Packet2ui& from) {
2681 EIGEN_DEBUG_UNALIGNED_STORE vst1_u32(to, from);
2682}
2683template <>
2684EIGEN_STRONG_INLINE void pstoreu<uint32_t>(uint32_t* to, const Packet4ui& from) {
2685 EIGEN_DEBUG_UNALIGNED_STORE vst1q_u32(to, from);
2686}
2687template <>
2688EIGEN_STRONG_INLINE void pstoreu<int64_t>(int64_t* to, const Packet2l& from) {
2689 EIGEN_DEBUG_UNALIGNED_STORE vst1q_s64(to, from);
2690}
2691template <>
2692EIGEN_STRONG_INLINE void pstoreu<uint64_t>(uint64_t* to, const Packet2ul& from) {
2693 EIGEN_DEBUG_UNALIGNED_STORE vst1q_u64(to, from);
2694}
2695
2696template <>
2697EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet2f pgather<float, Packet2f>(const float* from, Index stride) {
2698 Packet2f res = vld1_dup_f32(from);
2699 res = vld1_lane_f32(from + 1 * stride, res, 1);
2700 return res;
2701}
2702template <>
2703EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4f pgather<float, Packet4f>(const float* from, Index stride) {
2704 if (stride == 2) {
2705 // Overlap the loads so the second ends at the last gathered coefficient, from[6].
2706#if EIGEN_ARCH_ARM64
2707 // lo = [0 1 2 3], hi = [3 4 5 6]. GCC turns the equivalent vuzp2q(vrev64q(lo), hi) into a slower TBL.
2708 Packet4f lo = vld1q_f32(from);
2709 Packet4f hi = vld1q_f32(from + 3);
2710 return vcombine_f32(vget_low_f32(vuzp1q_f32(lo, lo)), vget_high_f32(vuzp2q_f32(hi, hi)));
2711#else
2712 return vcombine_f32(vld2_f32(from).val[0], vld2_f32(from + 3).val[1]);
2713#endif
2714 }
2715 Packet4f res = vld1q_dup_f32(from);
2716 res = vld1q_lane_f32(from + 1 * stride, res, 1);
2717 res = vld1q_lane_f32(from + 2 * stride, res, 2);
2718 res = vld1q_lane_f32(from + 3 * stride, res, 3);
2719 return res;
2720}
2721template <>
2722EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4c pgather<int8_t, Packet4c>(const int8_t* from, Index stride) {
2723 Packet4c res;
2724 for (int i = 0; i != 4; i++) reinterpret_cast<int8_t*>(&res)[i] = *(from + i * stride);
2725 return res;
2726}
2727template <>
2728EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8c pgather<int8_t, Packet8c>(const int8_t* from, Index stride) {
2729 Packet8c res = vld1_dup_s8(from);
2730 res = vld1_lane_s8(from + 1 * stride, res, 1);
2731 res = vld1_lane_s8(from + 2 * stride, res, 2);
2732 res = vld1_lane_s8(from + 3 * stride, res, 3);
2733 res = vld1_lane_s8(from + 4 * stride, res, 4);
2734 res = vld1_lane_s8(from + 5 * stride, res, 5);
2735 res = vld1_lane_s8(from + 6 * stride, res, 6);
2736 res = vld1_lane_s8(from + 7 * stride, res, 7);
2737 return res;
2738}
2739template <>
2740EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet16c pgather<int8_t, Packet16c>(const int8_t* from, Index stride) {
2741 Packet16c res = vld1q_dup_s8(from);
2742 res = vld1q_lane_s8(from + 1 * stride, res, 1);
2743 res = vld1q_lane_s8(from + 2 * stride, res, 2);
2744 res = vld1q_lane_s8(from + 3 * stride, res, 3);
2745 res = vld1q_lane_s8(from + 4 * stride, res, 4);
2746 res = vld1q_lane_s8(from + 5 * stride, res, 5);
2747 res = vld1q_lane_s8(from + 6 * stride, res, 6);
2748 res = vld1q_lane_s8(from + 7 * stride, res, 7);
2749 res = vld1q_lane_s8(from + 8 * stride, res, 8);
2750 res = vld1q_lane_s8(from + 9 * stride, res, 9);
2751 res = vld1q_lane_s8(from + 10 * stride, res, 10);
2752 res = vld1q_lane_s8(from + 11 * stride, res, 11);
2753 res = vld1q_lane_s8(from + 12 * stride, res, 12);
2754 res = vld1q_lane_s8(from + 13 * stride, res, 13);
2755 res = vld1q_lane_s8(from + 14 * stride, res, 14);
2756 res = vld1q_lane_s8(from + 15 * stride, res, 15);
2757 return res;
2758}
2759template <>
2760EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4uc pgather<uint8_t, Packet4uc>(const uint8_t* from, Index stride) {
2761 Packet4uc res;
2762 for (int i = 0; i != 4; i++) reinterpret_cast<uint8_t*>(&res)[i] = *(from + i * stride);
2763 return res;
2764}
2765template <>
2766EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8uc pgather<uint8_t, Packet8uc>(const uint8_t* from, Index stride) {
2767 Packet8uc res = vld1_dup_u8(from);
2768 res = vld1_lane_u8(from + 1 * stride, res, 1);
2769 res = vld1_lane_u8(from + 2 * stride, res, 2);
2770 res = vld1_lane_u8(from + 3 * stride, res, 3);
2771 res = vld1_lane_u8(from + 4 * stride, res, 4);
2772 res = vld1_lane_u8(from + 5 * stride, res, 5);
2773 res = vld1_lane_u8(from + 6 * stride, res, 6);
2774 res = vld1_lane_u8(from + 7 * stride, res, 7);
2775 return res;
2776}
2777template <>
2778EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet16uc pgather<uint8_t, Packet16uc>(const uint8_t* from, Index stride) {
2779 Packet16uc res = vld1q_dup_u8(from);
2780 res = vld1q_lane_u8(from + 1 * stride, res, 1);
2781 res = vld1q_lane_u8(from + 2 * stride, res, 2);
2782 res = vld1q_lane_u8(from + 3 * stride, res, 3);
2783 res = vld1q_lane_u8(from + 4 * stride, res, 4);
2784 res = vld1q_lane_u8(from + 5 * stride, res, 5);
2785 res = vld1q_lane_u8(from + 6 * stride, res, 6);
2786 res = vld1q_lane_u8(from + 7 * stride, res, 7);
2787 res = vld1q_lane_u8(from + 8 * stride, res, 8);
2788 res = vld1q_lane_u8(from + 9 * stride, res, 9);
2789 res = vld1q_lane_u8(from + 10 * stride, res, 10);
2790 res = vld1q_lane_u8(from + 11 * stride, res, 11);
2791 res = vld1q_lane_u8(from + 12 * stride, res, 12);
2792 res = vld1q_lane_u8(from + 13 * stride, res, 13);
2793 res = vld1q_lane_u8(from + 14 * stride, res, 14);
2794 res = vld1q_lane_u8(from + 15 * stride, res, 15);
2795 return res;
2796}
2797template <>
2798EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4s pgather<int16_t, Packet4s>(const int16_t* from, Index stride) {
2799 Packet4s res = vld1_dup_s16(from);
2800 res = vld1_lane_s16(from + 1 * stride, res, 1);
2801 res = vld1_lane_s16(from + 2 * stride, res, 2);
2802 res = vld1_lane_s16(from + 3 * stride, res, 3);
2803 return res;
2804}
2805template <>
2806EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8s pgather<int16_t, Packet8s>(const int16_t* from, Index stride) {
2807 Packet8s res = vld1q_dup_s16(from);
2808 res = vld1q_lane_s16(from + 1 * stride, res, 1);
2809 res = vld1q_lane_s16(from + 2 * stride, res, 2);
2810 res = vld1q_lane_s16(from + 3 * stride, res, 3);
2811 res = vld1q_lane_s16(from + 4 * stride, res, 4);
2812 res = vld1q_lane_s16(from + 5 * stride, res, 5);
2813 res = vld1q_lane_s16(from + 6 * stride, res, 6);
2814 res = vld1q_lane_s16(from + 7 * stride, res, 7);
2815 return res;
2816}
2817template <>
2818EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4us pgather<uint16_t, Packet4us>(const uint16_t* from, Index stride) {
2819 Packet4us res = vld1_dup_u16(from);
2820 res = vld1_lane_u16(from + 1 * stride, res, 1);
2821 res = vld1_lane_u16(from + 2 * stride, res, 2);
2822 res = vld1_lane_u16(from + 3 * stride, res, 3);
2823 return res;
2824}
2825template <>
2826EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8us pgather<uint16_t, Packet8us>(const uint16_t* from, Index stride) {
2827 Packet8us res = vld1q_dup_u16(from);
2828 res = vld1q_lane_u16(from + 1 * stride, res, 1);
2829 res = vld1q_lane_u16(from + 2 * stride, res, 2);
2830 res = vld1q_lane_u16(from + 3 * stride, res, 3);
2831 res = vld1q_lane_u16(from + 4 * stride, res, 4);
2832 res = vld1q_lane_u16(from + 5 * stride, res, 5);
2833 res = vld1q_lane_u16(from + 6 * stride, res, 6);
2834 res = vld1q_lane_u16(from + 7 * stride, res, 7);
2835 return res;
2836}
2837template <>
2838EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet2i pgather<int32_t, Packet2i>(const int32_t* from, Index stride) {
2839 Packet2i res = vld1_dup_s32(from);
2840 res = vld1_lane_s32(from + 1 * stride, res, 1);
2841 return res;
2842}
2843template <>
2844EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4i pgather<int32_t, Packet4i>(const int32_t* from, Index stride) {
2845 Packet4i res = vld1q_dup_s32(from);
2846 res = vld1q_lane_s32(from + 1 * stride, res, 1);
2847 res = vld1q_lane_s32(from + 2 * stride, res, 2);
2848 res = vld1q_lane_s32(from + 3 * stride, res, 3);
2849 return res;
2850}
2851template <>
2852EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet2ui pgather<uint32_t, Packet2ui>(const uint32_t* from, Index stride) {
2853 Packet2ui res = vld1_dup_u32(from);
2854 res = vld1_lane_u32(from + 1 * stride, res, 1);
2855 return res;
2856}
2857template <>
2858EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4ui pgather<uint32_t, Packet4ui>(const uint32_t* from, Index stride) {
2859 Packet4ui res = vld1q_dup_u32(from);
2860 res = vld1q_lane_u32(from + 1 * stride, res, 1);
2861 res = vld1q_lane_u32(from + 2 * stride, res, 2);
2862 res = vld1q_lane_u32(from + 3 * stride, res, 3);
2863 return res;
2864}
2865template <>
2866EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet2l pgather<int64_t, Packet2l>(const int64_t* from, Index stride) {
2867 Packet2l res = vld1q_dup_s64(from);
2868 res = vld1q_lane_s64(from + 1 * stride, res, 1);
2869 return res;
2870}
2871template <>
2872EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet2ul pgather<uint64_t, Packet2ul>(const uint64_t* from, Index stride) {
2873 Packet2ul res = vld1q_dup_u64(from);
2874 res = vld1q_lane_u64(from + 1 * stride, res, 1);
2875 return res;
2876}
2877
2878template <>
2879EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<float, Packet2f>(float* to, const Packet2f& from, Index stride) {
2880 vst1_lane_f32(to + stride * 0, from, 0);
2881 vst1_lane_f32(to + stride * 1, from, 1);
2882}
2883template <>
2884EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<float, Packet4f>(float* to, const Packet4f& from, Index stride) {
2885 vst1q_lane_f32(to + stride * 0, from, 0);
2886 vst1q_lane_f32(to + stride * 1, from, 1);
2887 vst1q_lane_f32(to + stride * 2, from, 2);
2888 vst1q_lane_f32(to + stride * 3, from, 3);
2889}
2890template <>
2891EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<int8_t, Packet4c>(int8_t* to, const Packet4c& from, Index stride) {
2892 for (int i = 0; i != 4; i++) *(to + i * stride) = reinterpret_cast<const int8_t*>(&from)[i];
2893}
2894template <>
2895EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<int8_t, Packet8c>(int8_t* to, const Packet8c& from, Index stride) {
2896 vst1_lane_s8(to + stride * 0, from, 0);
2897 vst1_lane_s8(to + stride * 1, from, 1);
2898 vst1_lane_s8(to + stride * 2, from, 2);
2899 vst1_lane_s8(to + stride * 3, from, 3);
2900 vst1_lane_s8(to + stride * 4, from, 4);
2901 vst1_lane_s8(to + stride * 5, from, 5);
2902 vst1_lane_s8(to + stride * 6, from, 6);
2903 vst1_lane_s8(to + stride * 7, from, 7);
2904}
2905template <>
2906EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<int8_t, Packet16c>(int8_t* to, const Packet16c& from,
2907 Index stride) {
2908 vst1q_lane_s8(to + stride * 0, from, 0);
2909 vst1q_lane_s8(to + stride * 1, from, 1);
2910 vst1q_lane_s8(to + stride * 2, from, 2);
2911 vst1q_lane_s8(to + stride * 3, from, 3);
2912 vst1q_lane_s8(to + stride * 4, from, 4);
2913 vst1q_lane_s8(to + stride * 5, from, 5);
2914 vst1q_lane_s8(to + stride * 6, from, 6);
2915 vst1q_lane_s8(to + stride * 7, from, 7);
2916 vst1q_lane_s8(to + stride * 8, from, 8);
2917 vst1q_lane_s8(to + stride * 9, from, 9);
2918 vst1q_lane_s8(to + stride * 10, from, 10);
2919 vst1q_lane_s8(to + stride * 11, from, 11);
2920 vst1q_lane_s8(to + stride * 12, from, 12);
2921 vst1q_lane_s8(to + stride * 13, from, 13);
2922 vst1q_lane_s8(to + stride * 14, from, 14);
2923 vst1q_lane_s8(to + stride * 15, from, 15);
2924}
2925template <>
2926EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<uint8_t, Packet4uc>(uint8_t* to, const Packet4uc& from,
2927 Index stride) {
2928 for (int i = 0; i != 4; i++) *(to + i * stride) = reinterpret_cast<const uint8_t*>(&from)[i];
2929}
2930template <>
2931EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<uint8_t, Packet8uc>(uint8_t* to, const Packet8uc& from,
2932 Index stride) {
2933 vst1_lane_u8(to + stride * 0, from, 0);
2934 vst1_lane_u8(to + stride * 1, from, 1);
2935 vst1_lane_u8(to + stride * 2, from, 2);
2936 vst1_lane_u8(to + stride * 3, from, 3);
2937 vst1_lane_u8(to + stride * 4, from, 4);
2938 vst1_lane_u8(to + stride * 5, from, 5);
2939 vst1_lane_u8(to + stride * 6, from, 6);
2940 vst1_lane_u8(to + stride * 7, from, 7);
2941}
2942template <>
2943EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<uint8_t, Packet16uc>(uint8_t* to, const Packet16uc& from,
2944 Index stride) {
2945 vst1q_lane_u8(to + stride * 0, from, 0);
2946 vst1q_lane_u8(to + stride * 1, from, 1);
2947 vst1q_lane_u8(to + stride * 2, from, 2);
2948 vst1q_lane_u8(to + stride * 3, from, 3);
2949 vst1q_lane_u8(to + stride * 4, from, 4);
2950 vst1q_lane_u8(to + stride * 5, from, 5);
2951 vst1q_lane_u8(to + stride * 6, from, 6);
2952 vst1q_lane_u8(to + stride * 7, from, 7);
2953 vst1q_lane_u8(to + stride * 8, from, 8);
2954 vst1q_lane_u8(to + stride * 9, from, 9);
2955 vst1q_lane_u8(to + stride * 10, from, 10);
2956 vst1q_lane_u8(to + stride * 11, from, 11);
2957 vst1q_lane_u8(to + stride * 12, from, 12);
2958 vst1q_lane_u8(to + stride * 13, from, 13);
2959 vst1q_lane_u8(to + stride * 14, from, 14);
2960 vst1q_lane_u8(to + stride * 15, from, 15);
2961}
2962template <>
2963EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<int16_t, Packet4s>(int16_t* to, const Packet4s& from,
2964 Index stride) {
2965 vst1_lane_s16(to + stride * 0, from, 0);
2966 vst1_lane_s16(to + stride * 1, from, 1);
2967 vst1_lane_s16(to + stride * 2, from, 2);
2968 vst1_lane_s16(to + stride * 3, from, 3);
2969}
2970template <>
2971EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<int16_t, Packet8s>(int16_t* to, const Packet8s& from,
2972 Index stride) {
2973 vst1q_lane_s16(to + stride * 0, from, 0);
2974 vst1q_lane_s16(to + stride * 1, from, 1);
2975 vst1q_lane_s16(to + stride * 2, from, 2);
2976 vst1q_lane_s16(to + stride * 3, from, 3);
2977 vst1q_lane_s16(to + stride * 4, from, 4);
2978 vst1q_lane_s16(to + stride * 5, from, 5);
2979 vst1q_lane_s16(to + stride * 6, from, 6);
2980 vst1q_lane_s16(to + stride * 7, from, 7);
2981}
2982template <>
2983EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<uint16_t, Packet4us>(uint16_t* to, const Packet4us& from,
2984 Index stride) {
2985 vst1_lane_u16(to + stride * 0, from, 0);
2986 vst1_lane_u16(to + stride * 1, from, 1);
2987 vst1_lane_u16(to + stride * 2, from, 2);
2988 vst1_lane_u16(to + stride * 3, from, 3);
2989}
2990template <>
2991EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<uint16_t, Packet8us>(uint16_t* to, const Packet8us& from,
2992 Index stride) {
2993 vst1q_lane_u16(to + stride * 0, from, 0);
2994 vst1q_lane_u16(to + stride * 1, from, 1);
2995 vst1q_lane_u16(to + stride * 2, from, 2);
2996 vst1q_lane_u16(to + stride * 3, from, 3);
2997 vst1q_lane_u16(to + stride * 4, from, 4);
2998 vst1q_lane_u16(to + stride * 5, from, 5);
2999 vst1q_lane_u16(to + stride * 6, from, 6);
3000 vst1q_lane_u16(to + stride * 7, from, 7);
3001}
3002template <>
3003EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<int32_t, Packet2i>(int32_t* to, const Packet2i& from,
3004 Index stride) {
3005 vst1_lane_s32(to + stride * 0, from, 0);
3006 vst1_lane_s32(to + stride * 1, from, 1);
3007}
3008template <>
3009EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<int32_t, Packet4i>(int32_t* to, const Packet4i& from,
3010 Index stride) {
3011 vst1q_lane_s32(to + stride * 0, from, 0);
3012 vst1q_lane_s32(to + stride * 1, from, 1);
3013 vst1q_lane_s32(to + stride * 2, from, 2);
3014 vst1q_lane_s32(to + stride * 3, from, 3);
3015}
3016template <>
3017EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<uint32_t, Packet2ui>(uint32_t* to, const Packet2ui& from,
3018 Index stride) {
3019 vst1_lane_u32(to + stride * 0, from, 0);
3020 vst1_lane_u32(to + stride * 1, from, 1);
3021}
3022template <>
3023EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<uint32_t, Packet4ui>(uint32_t* to, const Packet4ui& from,
3024 Index stride) {
3025 vst1q_lane_u32(to + stride * 0, from, 0);
3026 vst1q_lane_u32(to + stride * 1, from, 1);
3027 vst1q_lane_u32(to + stride * 2, from, 2);
3028 vst1q_lane_u32(to + stride * 3, from, 3);
3029}
3030template <>
3031EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<int64_t, Packet2l>(int64_t* to, const Packet2l& from,
3032 Index stride) {
3033 vst1q_lane_s64(to + stride * 0, from, 0);
3034 vst1q_lane_s64(to + stride * 1, from, 1);
3035}
3036template <>
3037EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<uint64_t, Packet2ul>(uint64_t* to, const Packet2ul& from,
3038 Index stride) {
3039 vst1q_lane_u64(to + stride * 0, from, 0);
3040 vst1q_lane_u64(to + stride * 1, from, 1);
3041}
3042
3043template <>
3044EIGEN_STRONG_INLINE void prefetch<float>(const float* addr) {
3045 EIGEN_ARM_PREFETCH(addr);
3046}
3047template <>
3048EIGEN_STRONG_INLINE void prefetch<int8_t>(const int8_t* addr) {
3049 EIGEN_ARM_PREFETCH(addr);
3050}
3051template <>
3052EIGEN_STRONG_INLINE void prefetch<uint8_t>(const uint8_t* addr) {
3053 EIGEN_ARM_PREFETCH(addr);
3054}
3055template <>
3056EIGEN_STRONG_INLINE void prefetch<int16_t>(const int16_t* addr) {
3057 EIGEN_ARM_PREFETCH(addr);
3058}
3059template <>
3060EIGEN_STRONG_INLINE void prefetch<uint16_t>(const uint16_t* addr) {
3061 EIGEN_ARM_PREFETCH(addr);
3062}
3063template <>
3064EIGEN_STRONG_INLINE void prefetch<int32_t>(const int32_t* addr) {
3065 EIGEN_ARM_PREFETCH(addr);
3066}
3067template <>
3068EIGEN_STRONG_INLINE void prefetch<uint32_t>(const uint32_t* addr) {
3069 EIGEN_ARM_PREFETCH(addr);
3070}
3071template <>
3072EIGEN_STRONG_INLINE void prefetch<int64_t>(const int64_t* addr) {
3073 EIGEN_ARM_PREFETCH(addr);
3074}
3075template <>
3076EIGEN_STRONG_INLINE void prefetch<uint64_t>(const uint64_t* addr) {
3077 EIGEN_ARM_PREFETCH(addr);
3078}
3079
3080template <>
3081EIGEN_STRONG_INLINE float pfirst<Packet2f>(const Packet2f& a) {
3082 return vget_lane_f32(a, 0);
3083}
3084template <>
3085EIGEN_STRONG_INLINE float pfirst<Packet4f>(const Packet4f& a) {
3086 return vgetq_lane_f32(a, 0);
3087}
3088template <>
3089EIGEN_STRONG_INLINE int8_t pfirst<Packet4c>(const Packet4c& a) {
3090 return static_cast<int8_t>(a & 0xff);
3091}
3092template <>
3093EIGEN_STRONG_INLINE int8_t pfirst<Packet8c>(const Packet8c& a) {
3094 return vget_lane_s8(a, 0);
3095}
3096template <>
3097EIGEN_STRONG_INLINE int8_t pfirst<Packet16c>(const Packet16c& a) {
3098 return vgetq_lane_s8(a, 0);
3099}
3100template <>
3101EIGEN_STRONG_INLINE uint8_t pfirst<Packet4uc>(const Packet4uc& a) {
3102 return static_cast<uint8_t>(a & 0xff);
3103}
3104template <>
3105EIGEN_STRONG_INLINE uint8_t pfirst<Packet8uc>(const Packet8uc& a) {
3106 return vget_lane_u8(a, 0);
3107}
3108template <>
3109EIGEN_STRONG_INLINE uint8_t pfirst<Packet16uc>(const Packet16uc& a) {
3110 return vgetq_lane_u8(a, 0);
3111}
3112template <>
3113EIGEN_STRONG_INLINE int16_t pfirst<Packet4s>(const Packet4s& a) {
3114 return vget_lane_s16(a, 0);
3115}
3116template <>
3117EIGEN_STRONG_INLINE int16_t pfirst<Packet8s>(const Packet8s& a) {
3118 return vgetq_lane_s16(a, 0);
3119}
3120template <>
3121EIGEN_STRONG_INLINE uint16_t pfirst<Packet4us>(const Packet4us& a) {
3122 return vget_lane_u16(a, 0);
3123}
3124template <>
3125EIGEN_STRONG_INLINE uint16_t pfirst<Packet8us>(const Packet8us& a) {
3126 return vgetq_lane_u16(a, 0);
3127}
3128template <>
3129EIGEN_STRONG_INLINE int32_t pfirst<Packet2i>(const Packet2i& a) {
3130 return vget_lane_s32(a, 0);
3131}
3132template <>
3133EIGEN_STRONG_INLINE int32_t pfirst<Packet4i>(const Packet4i& a) {
3134 return vgetq_lane_s32(a, 0);
3135}
3136template <>
3137EIGEN_STRONG_INLINE uint32_t pfirst<Packet2ui>(const Packet2ui& a) {
3138 return vget_lane_u32(a, 0);
3139}
3140template <>
3141EIGEN_STRONG_INLINE uint32_t pfirst<Packet4ui>(const Packet4ui& a) {
3142 return vgetq_lane_u32(a, 0);
3143}
3144template <>
3145EIGEN_STRONG_INLINE int64_t pfirst<Packet2l>(const Packet2l& a) {
3146 return vgetq_lane_s64(a, 0);
3147}
3148template <>
3149EIGEN_STRONG_INLINE uint64_t pfirst<Packet2ul>(const Packet2ul& a) {
3150 return vgetq_lane_u64(a, 0);
3151}
3152
3153template <>
3154EIGEN_STRONG_INLINE Packet2f preverse(const Packet2f& a) {
3155 return vrev64_f32(a);
3156}
3157template <>
3158EIGEN_STRONG_INLINE Packet4f preverse(const Packet4f& a) {
3159 const float32x4_t a_r64 = vrev64q_f32(a);
3160 return vcombine_f32(vget_high_f32(a_r64), vget_low_f32(a_r64));
3161}
3162template <>
3163EIGEN_STRONG_INLINE Packet4c preverse(const Packet4c& a) {
3164 return vget_lane_s32(vreinterpret_s32_s8(vrev64_s8(vreinterpret_s8_s32(vdup_n_s32(a)))), 0);
3165}
3166template <>
3167EIGEN_STRONG_INLINE Packet8c preverse(const Packet8c& a) {
3168 return vrev64_s8(a);
3169}
3170template <>
3171EIGEN_STRONG_INLINE Packet16c preverse(const Packet16c& a) {
3172 const int8x16_t a_r64 = vrev64q_s8(a);
3173 return vcombine_s8(vget_high_s8(a_r64), vget_low_s8(a_r64));
3174}
3175template <>
3176EIGEN_STRONG_INLINE Packet4uc preverse(const Packet4uc& a) {
3177 return vget_lane_u32(vreinterpret_u32_u8(vrev64_u8(vreinterpret_u8_u32(vdup_n_u32(a)))), 0);
3178}
3179template <>
3180EIGEN_STRONG_INLINE Packet8uc preverse(const Packet8uc& a) {
3181 return vrev64_u8(a);
3182}
3183template <>
3184EIGEN_STRONG_INLINE Packet16uc preverse(const Packet16uc& a) {
3185 const uint8x16_t a_r64 = vrev64q_u8(a);
3186 return vcombine_u8(vget_high_u8(a_r64), vget_low_u8(a_r64));
3187}
3188template <>
3189EIGEN_STRONG_INLINE Packet4s preverse(const Packet4s& a) {
3190 return vrev64_s16(a);
3191}
3192template <>
3193EIGEN_STRONG_INLINE Packet8s preverse(const Packet8s& a) {
3194 const int16x8_t a_r64 = vrev64q_s16(a);
3195 return vcombine_s16(vget_high_s16(a_r64), vget_low_s16(a_r64));
3196}
3197template <>
3198EIGEN_STRONG_INLINE Packet4us preverse(const Packet4us& a) {
3199 return vrev64_u16(a);
3200}
3201template <>
3202EIGEN_STRONG_INLINE Packet8us preverse(const Packet8us& a) {
3203 const uint16x8_t a_r64 = vrev64q_u16(a);
3204 return vcombine_u16(vget_high_u16(a_r64), vget_low_u16(a_r64));
3205}
3206template <>
3207EIGEN_STRONG_INLINE Packet2i preverse(const Packet2i& a) {
3208 return vrev64_s32(a);
3209}
3210template <>
3211EIGEN_STRONG_INLINE Packet4i preverse(const Packet4i& a) {
3212 const int32x4_t a_r64 = vrev64q_s32(a);
3213 return vcombine_s32(vget_high_s32(a_r64), vget_low_s32(a_r64));
3214}
3215template <>
3216EIGEN_STRONG_INLINE Packet2ui preverse(const Packet2ui& a) {
3217 return vrev64_u32(a);
3218}
3219template <>
3220EIGEN_STRONG_INLINE Packet4ui preverse(const Packet4ui& a) {
3221 const uint32x4_t a_r64 = vrev64q_u32(a);
3222 return vcombine_u32(vget_high_u32(a_r64), vget_low_u32(a_r64));
3223}
3224template <>
3225EIGEN_STRONG_INLINE Packet2l preverse(const Packet2l& a) {
3226 return vcombine_s64(vget_high_s64(a), vget_low_s64(a));
3227}
3228template <>
3229EIGEN_STRONG_INLINE Packet2ul preverse(const Packet2ul& a) {
3230 return vcombine_u64(vget_high_u64(a), vget_low_u64(a));
3231}
3232
3233template <>
3234EIGEN_STRONG_INLINE Packet2f pabs(const Packet2f& a) {
3235 return vabs_f32(a);
3236}
3237template <>
3238EIGEN_STRONG_INLINE Packet4f pabs(const Packet4f& a) {
3239 return vabsq_f32(a);
3240}
3241template <>
3242EIGEN_STRONG_INLINE Packet4c pabs<Packet4c>(const Packet4c& a) {
3243 return vget_lane_s32(vreinterpret_s32_s8(vabs_s8(vreinterpret_s8_s32(vdup_n_s32(a)))), 0);
3244}
3245template <>
3246EIGEN_STRONG_INLINE Packet8c pabs(const Packet8c& a) {
3247 return vabs_s8(a);
3248}
3249template <>
3250EIGEN_STRONG_INLINE Packet16c pabs(const Packet16c& a) {
3251 return vabsq_s8(a);
3252}
3253template <>
3254EIGEN_STRONG_INLINE Packet4s pabs(const Packet4s& a) {
3255 return vabs_s16(a);
3256}
3257template <>
3258EIGEN_STRONG_INLINE Packet8s pabs(const Packet8s& a) {
3259 return vabsq_s16(a);
3260}
3261template <>
3262EIGEN_STRONG_INLINE Packet2i pabs(const Packet2i& a) {
3263 return vabs_s32(a);
3264}
3265template <>
3266EIGEN_STRONG_INLINE Packet4i pabs(const Packet4i& a) {
3267 return vabsq_s32(a);
3268}
3269template <>
3270EIGEN_STRONG_INLINE Packet2l pabs(const Packet2l& a) {
3271#if EIGEN_ARCH_ARM64
3272 return vabsq_s64(a);
3273#else
3274 // NOTE: From <https://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs>. The addition is
3275 // done in the unsigned domain: at `a == INT64_MIN`, `mask == -1`, so the signed `a + mask` is UB
3276 // (it wraps to INT64_MIN on every real target, which is exactly what's needed here).
3277 const int64x2_t mask = vshrq_n_s64(a, 63);
3278 const uint64x2_t sum = vaddq_u64(vreinterpretq_u64_s64(a), vreinterpretq_u64_s64(mask));
3279 return veorq_s64(vreinterpretq_s64_u64(sum), mask);
3280#endif
3281}
3282template <>
3283EIGEN_STRONG_INLINE Packet2f psignbit(const Packet2f& a) {
3284 return vreinterpret_f32_s32(vshr_n_s32(vreinterpret_s32_f32(a), 31));
3285}
3286template <>
3287EIGEN_STRONG_INLINE Packet4f psignbit(const Packet4f& a) {
3288 return vreinterpretq_f32_s32(vshrq_n_s32(vreinterpretq_s32_f32(a), 31));
3289}
3290
3291template <>
3292EIGEN_STRONG_INLINE Packet2f pfrexp<Packet2f>(const Packet2f& a, Packet2f& exponent) {
3293 return pfrexp_generic(a, exponent);
3294}
3295template <>
3296EIGEN_STRONG_INLINE Packet4f pfrexp<Packet4f>(const Packet4f& a, Packet4f& exponent) {
3297 return pfrexp_generic(a, exponent);
3298}
3299
3300template <>
3301EIGEN_STRONG_INLINE Packet2f pldexp<Packet2f>(const Packet2f& a, const Packet2f& exponent) {
3302 return pldexp_generic(a, exponent);
3303}
3304template <>
3305EIGEN_STRONG_INLINE Packet4f pldexp<Packet4f>(const Packet4f& a, const Packet4f& exponent) {
3306 return pldexp_generic(a, exponent);
3307}
3308
3309#if EIGEN_ARCH_ARM64
3310template <>
3311EIGEN_STRONG_INLINE float predux<Packet2f>(const Packet2f& a) {
3312 return vaddv_f32(a);
3313}
3314template <>
3315EIGEN_STRONG_INLINE float predux<Packet4f>(const Packet4f& a) {
3316 return vaddvq_f32(a);
3317}
3318
3319template <>
3320EIGEN_STRONG_INLINE Index predux_count(const Packet4f& a) {
3321 const uint32x4_t nonzero = vbicq_u32(vdupq_n_u32(1), vceqq_f32(a, vdupq_n_f32(0.0f)));
3322 return static_cast<Index>(vaddvq_u32(nonzero));
3323}
3324#else
3325template <>
3326EIGEN_STRONG_INLINE float predux<Packet2f>(const Packet2f& a) {
3327 return vget_lane_f32(vpadd_f32(a, a), 0);
3328}
3329template <>
3330EIGEN_STRONG_INLINE float predux<Packet4f>(const Packet4f& a) {
3331 const float32x2_t sum = vadd_f32(vget_low_f32(a), vget_high_f32(a));
3332 return vget_lane_f32(vpadd_f32(sum, sum), 0);
3333}
3334#endif
3335template <>
3336EIGEN_STRONG_INLINE int8_t predux<Packet4c>(const Packet4c& a) {
3337 const int8x8_t a_dup = vreinterpret_s8_s32(vdup_n_s32(a));
3338 int8x8_t sum = vpadd_s8(a_dup, a_dup);
3339 sum = vpadd_s8(sum, sum);
3340 return vget_lane_s8(sum, 0);
3341}
3342#if EIGEN_ARCH_ARM64
3343template <>
3344EIGEN_STRONG_INLINE int8_t predux<Packet8c>(const Packet8c& a) {
3345 return vaddv_s8(a);
3346}
3347template <>
3348EIGEN_STRONG_INLINE int8_t predux<Packet16c>(const Packet16c& a) {
3349 return vaddvq_s8(a);
3350}
3351#else
3352template <>
3353EIGEN_STRONG_INLINE int8_t predux<Packet8c>(const Packet8c& a) {
3354 int8x8_t sum = vpadd_s8(a, a);
3355 sum = vpadd_s8(sum, sum);
3356 sum = vpadd_s8(sum, sum);
3357 return vget_lane_s8(sum, 0);
3358}
3359template <>
3360EIGEN_STRONG_INLINE int8_t predux<Packet16c>(const Packet16c& a) {
3361 int8x8_t sum = vadd_s8(vget_low_s8(a), vget_high_s8(a));
3362 sum = vpadd_s8(sum, sum);
3363 sum = vpadd_s8(sum, sum);
3364 sum = vpadd_s8(sum, sum);
3365 return vget_lane_s8(sum, 0);
3366}
3367#endif
3368template <>
3369EIGEN_STRONG_INLINE uint8_t predux<Packet4uc>(const Packet4uc& a) {
3370 const uint8x8_t a_dup = vreinterpret_u8_u32(vdup_n_u32(a));
3371 uint8x8_t sum = vpadd_u8(a_dup, a_dup);
3372 sum = vpadd_u8(sum, sum);
3373 return vget_lane_u8(sum, 0);
3374}
3375#if EIGEN_ARCH_ARM64
3376template <>
3377EIGEN_STRONG_INLINE uint8_t predux<Packet8uc>(const Packet8uc& a) {
3378 return vaddv_u8(a);
3379}
3380template <>
3381EIGEN_STRONG_INLINE uint8_t predux<Packet16uc>(const Packet16uc& a) {
3382 return vaddvq_u8(a);
3383}
3384template <>
3385EIGEN_STRONG_INLINE int16_t predux<Packet4s>(const Packet4s& a) {
3386 return vaddv_s16(a);
3387}
3388template <>
3389EIGEN_STRONG_INLINE int16_t predux<Packet8s>(const Packet8s& a) {
3390 return vaddvq_s16(a);
3391}
3392template <>
3393EIGEN_STRONG_INLINE uint16_t predux<Packet4us>(const Packet4us& a) {
3394 return vaddv_u16(a);
3395}
3396template <>
3397EIGEN_STRONG_INLINE uint16_t predux<Packet8us>(const Packet8us& a) {
3398 return vaddvq_u16(a);
3399}
3400template <>
3401EIGEN_STRONG_INLINE int32_t predux<Packet2i>(const Packet2i& a) {
3402 return vaddv_s32(a);
3403}
3404template <>
3405EIGEN_STRONG_INLINE int32_t predux<Packet4i>(const Packet4i& a) {
3406 return vaddvq_s32(a);
3407}
3408template <>
3409EIGEN_STRONG_INLINE uint32_t predux<Packet2ui>(const Packet2ui& a) {
3410 return vaddv_u32(a);
3411}
3412template <>
3413EIGEN_STRONG_INLINE uint32_t predux<Packet4ui>(const Packet4ui& a) {
3414 return vaddvq_u32(a);
3415}
3416template <>
3417EIGEN_STRONG_INLINE int64_t predux<Packet2l>(const Packet2l& a) {
3418 return vaddvq_s64(a);
3419}
3420template <>
3421EIGEN_STRONG_INLINE uint64_t predux<Packet2ul>(const Packet2ul& a) {
3422 return vaddvq_u64(a);
3423}
3424#else
3425template <>
3426EIGEN_STRONG_INLINE uint8_t predux<Packet8uc>(const Packet8uc& a) {
3427 uint8x8_t sum = vpadd_u8(a, a);
3428 sum = vpadd_u8(sum, sum);
3429 sum = vpadd_u8(sum, sum);
3430 return vget_lane_u8(sum, 0);
3431}
3432template <>
3433EIGEN_STRONG_INLINE uint8_t predux<Packet16uc>(const Packet16uc& a) {
3434 uint8x8_t sum = vadd_u8(vget_low_u8(a), vget_high_u8(a));
3435 sum = vpadd_u8(sum, sum);
3436 sum = vpadd_u8(sum, sum);
3437 sum = vpadd_u8(sum, sum);
3438 return vget_lane_u8(sum, 0);
3439}
3440template <>
3441EIGEN_STRONG_INLINE int16_t predux<Packet4s>(const Packet4s& a) {
3442 const int16x4_t sum = vpadd_s16(a, a);
3443 return vget_lane_s16(vpadd_s16(sum, sum), 0);
3444}
3445template <>
3446EIGEN_STRONG_INLINE int16_t predux<Packet8s>(const Packet8s& a) {
3447 int16x4_t sum = vadd_s16(vget_low_s16(a), vget_high_s16(a));
3448 sum = vpadd_s16(sum, sum);
3449 sum = vpadd_s16(sum, sum);
3450 return vget_lane_s16(sum, 0);
3451}
3452template <>
3453EIGEN_STRONG_INLINE uint16_t predux<Packet4us>(const Packet4us& a) {
3454 const uint16x4_t sum = vpadd_u16(a, a);
3455 return vget_lane_u16(vpadd_u16(sum, sum), 0);
3456}
3457template <>
3458EIGEN_STRONG_INLINE uint16_t predux<Packet8us>(const Packet8us& a) {
3459 uint16x4_t sum = vadd_u16(vget_low_u16(a), vget_high_u16(a));
3460 sum = vpadd_u16(sum, sum);
3461 sum = vpadd_u16(sum, sum);
3462 return vget_lane_u16(sum, 0);
3463}
3464template <>
3465EIGEN_STRONG_INLINE int32_t predux<Packet2i>(const Packet2i& a) {
3466 return vget_lane_s32(vpadd_s32(a, a), 0);
3467}
3468template <>
3469EIGEN_STRONG_INLINE int32_t predux<Packet4i>(const Packet4i& a) {
3470 const int32x2_t sum = vadd_s32(vget_low_s32(a), vget_high_s32(a));
3471 return vget_lane_s32(vpadd_s32(sum, sum), 0);
3472}
3473template <>
3474EIGEN_STRONG_INLINE uint32_t predux<Packet2ui>(const Packet2ui& a) {
3475 return vget_lane_u32(vpadd_u32(a, a), 0);
3476}
3477template <>
3478EIGEN_STRONG_INLINE uint32_t predux<Packet4ui>(const Packet4ui& a) {
3479 const uint32x2_t sum = vadd_u32(vget_low_u32(a), vget_high_u32(a));
3480 return vget_lane_u32(vpadd_u32(sum, sum), 0);
3481}
3482template <>
3483EIGEN_STRONG_INLINE int64_t predux<Packet2l>(const Packet2l& a) {
3484 return vgetq_lane_s64(a, 0) + vgetq_lane_s64(a, 1);
3485}
3486template <>
3487EIGEN_STRONG_INLINE uint64_t predux<Packet2ul>(const Packet2ul& a) {
3488 return vgetq_lane_u64(a, 0) + vgetq_lane_u64(a, 1);
3489}
3490#endif
3491
3492template <>
3493EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4c predux_half(const Packet8c& a) {
3494 return vget_lane_s32(vreinterpret_s32_s8(vadd_s8(a, vreinterpret_s8_s32(vrev64_s32(vreinterpret_s32_s8(a))))), 0);
3495}
3496template <>
3497EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8c predux_half(const Packet16c& a) {
3498 return vadd_s8(vget_high_s8(a), vget_low_s8(a));
3499}
3500template <>
3501EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4uc predux_half(const Packet8uc& a) {
3502 return vget_lane_u32(vreinterpret_u32_u8(vadd_u8(a, vreinterpret_u8_u32(vrev64_u32(vreinterpret_u32_u8(a))))), 0);
3503}
3504template <>
3505EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8uc predux_half(const Packet16uc& a) {
3506 return vadd_u8(vget_high_u8(a), vget_low_u8(a));
3507}
3508template <>
3509EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4s predux_half(const Packet8s& a) {
3510 return vadd_s16(vget_high_s16(a), vget_low_s16(a));
3511}
3512template <>
3513EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4us predux_half(const Packet8us& a) {
3514 return vadd_u16(vget_high_u16(a), vget_low_u16(a));
3515}
3516
3517// Other reduction functions:
3518// mul
3519template <>
3520EIGEN_STRONG_INLINE float predux_mul<Packet2f>(const Packet2f& a) {
3521 return vget_lane_f32(a, 0) * vget_lane_f32(a, 1);
3522}
3523template <>
3524EIGEN_STRONG_INLINE float predux_mul<Packet4f>(const Packet4f& a) {
3525 return predux_mul<Packet2f>(vmul_f32(vget_low_f32(a), vget_high_f32(a)));
3526}
3527template <>
3528EIGEN_STRONG_INLINE int8_t predux_mul<Packet4c>(const Packet4c& a) {
3529 int8x8_t prod = vreinterpret_s8_s32(vdup_n_s32(a));
3530 prod = vmul_s8(prod, vrev16_s8(prod));
3531 return vget_lane_s8(prod, 0) * vget_lane_s8(prod, 2);
3532}
3533template <>
3534EIGEN_STRONG_INLINE int8_t predux_mul<Packet8c>(const Packet8c& a) {
3535 int8x8_t prod = vmul_s8(a, vrev16_s8(a));
3536 prod = vmul_s8(prod, vrev32_s8(prod));
3537 return vget_lane_s8(prod, 0) * vget_lane_s8(prod, 4);
3538}
3539template <>
3540EIGEN_STRONG_INLINE int8_t predux_mul<Packet16c>(const Packet16c& a) {
3541 return predux_mul<Packet8c>(vmul_s8(vget_low_s8(a), vget_high_s8(a)));
3542}
3543template <>
3544EIGEN_STRONG_INLINE uint8_t predux_mul<Packet4uc>(const Packet4uc& a) {
3545 uint8x8_t prod = vreinterpret_u8_u32(vdup_n_u32(a));
3546 prod = vmul_u8(prod, vrev16_u8(prod));
3547 return vget_lane_u8(prod, 0) * vget_lane_u8(prod, 2);
3548}
3549template <>
3550EIGEN_STRONG_INLINE uint8_t predux_mul<Packet8uc>(const Packet8uc& a) {
3551 uint8x8_t prod = vmul_u8(a, vrev16_u8(a));
3552 prod = vmul_u8(prod, vrev32_u8(prod));
3553 return vget_lane_u8(prod, 0) * vget_lane_u8(prod, 4);
3554}
3555template <>
3556EIGEN_STRONG_INLINE uint8_t predux_mul<Packet16uc>(const Packet16uc& a) {
3557 return predux_mul<Packet8uc>(vmul_u8(vget_low_u8(a), vget_high_u8(a)));
3558}
3559template <>
3560EIGEN_STRONG_INLINE int16_t predux_mul<Packet4s>(const Packet4s& a) {
3561 const int16x4_t prod = vmul_s16(a, vrev32_s16(a));
3562 return vget_lane_s16(prod, 0) * vget_lane_s16(prod, 2);
3563}
3564template <>
3565EIGEN_STRONG_INLINE int16_t predux_mul<Packet8s>(const Packet8s& a) {
3566 int16x4_t prod;
3567
3568 // Get the product of a_lo * a_hi -> |a1*a5|a2*a6|a3*a7|a4*a8|
3569 prod = vmul_s16(vget_low_s16(a), vget_high_s16(a));
3570 // Swap and multiply |a1*a5*a2*a6|a3*a7*a4*a8|
3571 prod = vmul_s16(prod, vrev32_s16(prod));
3572 // Multiply |a1*a5*a2*a6*a3*a7*a4*a8|
3573 return vget_lane_s16(prod, 0) * vget_lane_s16(prod, 2);
3574}
3575template <>
3576EIGEN_STRONG_INLINE uint16_t predux_mul<Packet4us>(const Packet4us& a) {
3577 const uint16x4_t prod = vmul_u16(a, vrev32_u16(a));
3578 return vget_lane_u16(prod, 0) * vget_lane_u16(prod, 2);
3579}
3580template <>
3581EIGEN_STRONG_INLINE uint16_t predux_mul<Packet8us>(const Packet8us& a) {
3582 uint16x4_t prod;
3583
3584 // Get the product of a_lo * a_hi -> |a1*a5|a2*a6|a3*a7|a4*a8|
3585 prod = vmul_u16(vget_low_u16(a), vget_high_u16(a));
3586 // Swap and multiply |a1*a5*a2*a6|a3*a7*a4*a8|
3587 prod = vmul_u16(prod, vrev32_u16(prod));
3588 // Multiply |a1*a5*a2*a6*a3*a7*a4*a8|
3589 return vget_lane_u16(prod, 0) * vget_lane_u16(prod, 2);
3590}
3591template <>
3592EIGEN_STRONG_INLINE int32_t predux_mul<Packet2i>(const Packet2i& a) {
3593 return vget_lane_s32(a, 0) * vget_lane_s32(a, 1);
3594}
3595template <>
3596EIGEN_STRONG_INLINE int32_t predux_mul<Packet4i>(const Packet4i& a) {
3597 return predux_mul<Packet2i>(vmul_s32(vget_low_s32(a), vget_high_s32(a)));
3598}
3599template <>
3600EIGEN_STRONG_INLINE uint32_t predux_mul<Packet2ui>(const Packet2ui& a) {
3601 return vget_lane_u32(a, 0) * vget_lane_u32(a, 1);
3602}
3603template <>
3604EIGEN_STRONG_INLINE uint32_t predux_mul<Packet4ui>(const Packet4ui& a) {
3605 return predux_mul<Packet2ui>(vmul_u32(vget_low_u32(a), vget_high_u32(a)));
3606}
3607template <>
3608EIGEN_STRONG_INLINE int64_t predux_mul<Packet2l>(const Packet2l& a) {
3609 return vgetq_lane_s64(a, 0) * vgetq_lane_s64(a, 1);
3610}
3611template <>
3612EIGEN_STRONG_INLINE uint64_t predux_mul<Packet2ul>(const Packet2ul& a) {
3613 return vgetq_lane_u64(a, 0) * vgetq_lane_u64(a, 1);
3614}
3615
3616// min
3617#if EIGEN_ARCH_ARM64
3618template <>
3619EIGEN_STRONG_INLINE float predux_min<Packet2f>(const Packet2f& a) {
3620 return vminv_f32(a);
3621}
3622template <>
3623EIGEN_STRONG_INLINE float predux_min<Packet4f>(const Packet4f& a) {
3624 return vminvq_f32(a);
3625}
3626#else
3627template <>
3628EIGEN_STRONG_INLINE float predux_min<Packet2f>(const Packet2f& a) {
3629 return vget_lane_f32(vpmin_f32(a, a), 0);
3630}
3631template <>
3632EIGEN_STRONG_INLINE float predux_min<Packet4f>(const Packet4f& a) {
3633 const float32x2_t min = vmin_f32(vget_low_f32(a), vget_high_f32(a));
3634 return vget_lane_f32(vpmin_f32(min, min), 0);
3635}
3636#endif
3637template <>
3638EIGEN_STRONG_INLINE int8_t predux_min<Packet4c>(const Packet4c& a) {
3639 const int8x8_t a_dup = vreinterpret_s8_s32(vdup_n_s32(a));
3640 int8x8_t min = vpmin_s8(a_dup, a_dup);
3641 min = vpmin_s8(min, min);
3642 return vget_lane_s8(min, 0);
3643}
3644#if EIGEN_ARCH_ARM64
3645template <>
3646EIGEN_STRONG_INLINE int8_t predux_min<Packet8c>(const Packet8c& a) {
3647 return vminv_s8(a);
3648}
3649template <>
3650EIGEN_STRONG_INLINE int8_t predux_min<Packet16c>(const Packet16c& a) {
3651 return vminvq_s8(a);
3652}
3653#else
3654template <>
3655EIGEN_STRONG_INLINE int8_t predux_min<Packet8c>(const Packet8c& a) {
3656 int8x8_t min = vpmin_s8(a, a);
3657 min = vpmin_s8(min, min);
3658 min = vpmin_s8(min, min);
3659 return vget_lane_s8(min, 0);
3660}
3661template <>
3662EIGEN_STRONG_INLINE int8_t predux_min<Packet16c>(const Packet16c& a) {
3663 int8x8_t min = vmin_s8(vget_low_s8(a), vget_high_s8(a));
3664 min = vpmin_s8(min, min);
3665 min = vpmin_s8(min, min);
3666 min = vpmin_s8(min, min);
3667 return vget_lane_s8(min, 0);
3668}
3669#endif
3670template <>
3671EIGEN_STRONG_INLINE uint8_t predux_min<Packet4uc>(const Packet4uc& a) {
3672 const uint8x8_t a_dup = vreinterpret_u8_u32(vdup_n_u32(a));
3673 uint8x8_t min = vpmin_u8(a_dup, a_dup);
3674 min = vpmin_u8(min, min);
3675 return vget_lane_u8(min, 0);
3676}
3677#if EIGEN_ARCH_ARM64
3678template <>
3679EIGEN_STRONG_INLINE uint8_t predux_min<Packet8uc>(const Packet8uc& a) {
3680 return vminv_u8(a);
3681}
3682template <>
3683EIGEN_STRONG_INLINE uint8_t predux_min<Packet16uc>(const Packet16uc& a) {
3684 return vminvq_u8(a);
3685}
3686template <>
3687EIGEN_STRONG_INLINE int16_t predux_min<Packet4s>(const Packet4s& a) {
3688 return vminv_s16(a);
3689}
3690template <>
3691EIGEN_STRONG_INLINE int16_t predux_min<Packet8s>(const Packet8s& a) {
3692 return vminvq_s16(a);
3693}
3694template <>
3695EIGEN_STRONG_INLINE uint16_t predux_min<Packet4us>(const Packet4us& a) {
3696 return vminv_u16(a);
3697}
3698template <>
3699EIGEN_STRONG_INLINE uint16_t predux_min<Packet8us>(const Packet8us& a) {
3700 return vminvq_u16(a);
3701}
3702template <>
3703EIGEN_STRONG_INLINE int32_t predux_min<Packet2i>(const Packet2i& a) {
3704 return vminv_s32(a);
3705}
3706template <>
3707EIGEN_STRONG_INLINE int32_t predux_min<Packet4i>(const Packet4i& a) {
3708 return vminvq_s32(a);
3709}
3710template <>
3711EIGEN_STRONG_INLINE uint32_t predux_min<Packet2ui>(const Packet2ui& a) {
3712 return vminv_u32(a);
3713}
3714template <>
3715EIGEN_STRONG_INLINE uint32_t predux_min<Packet4ui>(const Packet4ui& a) {
3716 return vminvq_u32(a);
3717}
3718#else
3719template <>
3720EIGEN_STRONG_INLINE uint8_t predux_min<Packet8uc>(const Packet8uc& a) {
3721 uint8x8_t min = vpmin_u8(a, a);
3722 min = vpmin_u8(min, min);
3723 min = vpmin_u8(min, min);
3724 return vget_lane_u8(min, 0);
3725}
3726template <>
3727EIGEN_STRONG_INLINE uint8_t predux_min<Packet16uc>(const Packet16uc& a) {
3728 uint8x8_t min = vmin_u8(vget_low_u8(a), vget_high_u8(a));
3729 min = vpmin_u8(min, min);
3730 min = vpmin_u8(min, min);
3731 min = vpmin_u8(min, min);
3732 return vget_lane_u8(min, 0);
3733}
3734template <>
3735EIGEN_STRONG_INLINE int16_t predux_min<Packet4s>(const Packet4s& a) {
3736 const int16x4_t min = vpmin_s16(a, a);
3737 return vget_lane_s16(vpmin_s16(min, min), 0);
3738}
3739template <>
3740EIGEN_STRONG_INLINE int16_t predux_min<Packet8s>(const Packet8s& a) {
3741 int16x4_t min = vmin_s16(vget_low_s16(a), vget_high_s16(a));
3742 min = vpmin_s16(min, min);
3743 min = vpmin_s16(min, min);
3744 return vget_lane_s16(min, 0);
3745}
3746template <>
3747EIGEN_STRONG_INLINE uint16_t predux_min<Packet4us>(const Packet4us& a) {
3748 const uint16x4_t min = vpmin_u16(a, a);
3749 return vget_lane_u16(vpmin_u16(min, min), 0);
3750}
3751template <>
3752EIGEN_STRONG_INLINE uint16_t predux_min<Packet8us>(const Packet8us& a) {
3753 uint16x4_t min = vmin_u16(vget_low_u16(a), vget_high_u16(a));
3754 min = vpmin_u16(min, min);
3755 min = vpmin_u16(min, min);
3756 return vget_lane_u16(min, 0);
3757}
3758template <>
3759EIGEN_STRONG_INLINE int32_t predux_min<Packet2i>(const Packet2i& a) {
3760 return vget_lane_s32(vpmin_s32(a, a), 0);
3761}
3762template <>
3763EIGEN_STRONG_INLINE int32_t predux_min<Packet4i>(const Packet4i& a) {
3764 const int32x2_t min = vmin_s32(vget_low_s32(a), vget_high_s32(a));
3765 return vget_lane_s32(vpmin_s32(min, min), 0);
3766}
3767template <>
3768EIGEN_STRONG_INLINE uint32_t predux_min<Packet2ui>(const Packet2ui& a) {
3769 return vget_lane_u32(vpmin_u32(a, a), 0);
3770}
3771template <>
3772EIGEN_STRONG_INLINE uint32_t predux_min<Packet4ui>(const Packet4ui& a) {
3773 const uint32x2_t min = vmin_u32(vget_low_u32(a), vget_high_u32(a));
3774 return vget_lane_u32(vpmin_u32(min, min), 0);
3775}
3776#endif
3777template <>
3778EIGEN_STRONG_INLINE int64_t predux_min<Packet2l>(const Packet2l& a) {
3779 return (std::min)(vgetq_lane_s64(a, 0), vgetq_lane_s64(a, 1));
3780}
3781template <>
3782EIGEN_STRONG_INLINE uint64_t predux_min<Packet2ul>(const Packet2ul& a) {
3783 return (std::min)(vgetq_lane_u64(a, 0), vgetq_lane_u64(a, 1));
3784}
3785
3786// max
3787#if EIGEN_ARCH_ARM64
3788template <>
3789EIGEN_STRONG_INLINE float predux_max<Packet2f>(const Packet2f& a) {
3790 return vmaxv_f32(a);
3791}
3792template <>
3793EIGEN_STRONG_INLINE float predux_max<Packet4f>(const Packet4f& a) {
3794 return vmaxvq_f32(a);
3795}
3796#else
3797template <>
3798EIGEN_STRONG_INLINE float predux_max<Packet2f>(const Packet2f& a) {
3799 return vget_lane_f32(vpmax_f32(a, a), 0);
3800}
3801template <>
3802EIGEN_STRONG_INLINE float predux_max<Packet4f>(const Packet4f& a) {
3803 const float32x2_t max = vmax_f32(vget_low_f32(a), vget_high_f32(a));
3804 return vget_lane_f32(vpmax_f32(max, max), 0);
3805}
3806#endif
3807template <>
3808EIGEN_STRONG_INLINE int8_t predux_max<Packet4c>(const Packet4c& a) {
3809 const int8x8_t a_dup = vreinterpret_s8_s32(vdup_n_s32(a));
3810 int8x8_t max = vpmax_s8(a_dup, a_dup);
3811 max = vpmax_s8(max, max);
3812 return vget_lane_s8(max, 0);
3813}
3814#if EIGEN_ARCH_ARM64
3815template <>
3816EIGEN_STRONG_INLINE int8_t predux_max<Packet8c>(const Packet8c& a) {
3817 return vmaxv_s8(a);
3818}
3819template <>
3820EIGEN_STRONG_INLINE int8_t predux_max<Packet16c>(const Packet16c& a) {
3821 return vmaxvq_s8(a);
3822}
3823#else
3824template <>
3825EIGEN_STRONG_INLINE int8_t predux_max<Packet8c>(const Packet8c& a) {
3826 int8x8_t max = vpmax_s8(a, a);
3827 max = vpmax_s8(max, max);
3828 max = vpmax_s8(max, max);
3829 return vget_lane_s8(max, 0);
3830}
3831template <>
3832EIGEN_STRONG_INLINE int8_t predux_max<Packet16c>(const Packet16c& a) {
3833 int8x8_t max = vmax_s8(vget_low_s8(a), vget_high_s8(a));
3834 max = vpmax_s8(max, max);
3835 max = vpmax_s8(max, max);
3836 max = vpmax_s8(max, max);
3837 return vget_lane_s8(max, 0);
3838}
3839#endif
3840template <>
3841EIGEN_STRONG_INLINE uint8_t predux_max<Packet4uc>(const Packet4uc& a) {
3842 const uint8x8_t a_dup = vreinterpret_u8_u32(vdup_n_u32(a));
3843 uint8x8_t max = vpmax_u8(a_dup, a_dup);
3844 max = vpmax_u8(max, max);
3845 return vget_lane_u8(max, 0);
3846}
3847#if EIGEN_ARCH_ARM64
3848template <>
3849EIGEN_STRONG_INLINE uint8_t predux_max<Packet8uc>(const Packet8uc& a) {
3850 return vmaxv_u8(a);
3851}
3852template <>
3853EIGEN_STRONG_INLINE uint8_t predux_max<Packet16uc>(const Packet16uc& a) {
3854 return vmaxvq_u8(a);
3855}
3856template <>
3857EIGEN_STRONG_INLINE int16_t predux_max<Packet4s>(const Packet4s& a) {
3858 return vmaxv_s16(a);
3859}
3860template <>
3861EIGEN_STRONG_INLINE int16_t predux_max<Packet8s>(const Packet8s& a) {
3862 return vmaxvq_s16(a);
3863}
3864template <>
3865EIGEN_STRONG_INLINE uint16_t predux_max<Packet4us>(const Packet4us& a) {
3866 return vmaxv_u16(a);
3867}
3868template <>
3869EIGEN_STRONG_INLINE uint16_t predux_max<Packet8us>(const Packet8us& a) {
3870 return vmaxvq_u16(a);
3871}
3872template <>
3873EIGEN_STRONG_INLINE int32_t predux_max<Packet2i>(const Packet2i& a) {
3874 return vmaxv_s32(a);
3875}
3876template <>
3877EIGEN_STRONG_INLINE int32_t predux_max<Packet4i>(const Packet4i& a) {
3878 return vmaxvq_s32(a);
3879}
3880template <>
3881EIGEN_STRONG_INLINE uint32_t predux_max<Packet2ui>(const Packet2ui& a) {
3882 return vmaxv_u32(a);
3883}
3884template <>
3885EIGEN_STRONG_INLINE uint32_t predux_max<Packet4ui>(const Packet4ui& a) {
3886 return vmaxvq_u32(a);
3887}
3888#else
3889template <>
3890EIGEN_STRONG_INLINE uint8_t predux_max<Packet8uc>(const Packet8uc& a) {
3891 uint8x8_t max = vpmax_u8(a, a);
3892 max = vpmax_u8(max, max);
3893 max = vpmax_u8(max, max);
3894 return vget_lane_u8(max, 0);
3895}
3896template <>
3897EIGEN_STRONG_INLINE uint8_t predux_max<Packet16uc>(const Packet16uc& a) {
3898 uint8x8_t max = vmax_u8(vget_low_u8(a), vget_high_u8(a));
3899 max = vpmax_u8(max, max);
3900 max = vpmax_u8(max, max);
3901 max = vpmax_u8(max, max);
3902 return vget_lane_u8(max, 0);
3903}
3904template <>
3905EIGEN_STRONG_INLINE int16_t predux_max<Packet4s>(const Packet4s& a) {
3906 const int16x4_t max = vpmax_s16(a, a);
3907 return vget_lane_s16(vpmax_s16(max, max), 0);
3908}
3909template <>
3910EIGEN_STRONG_INLINE int16_t predux_max<Packet8s>(const Packet8s& a) {
3911 int16x4_t max = vmax_s16(vget_low_s16(a), vget_high_s16(a));
3912 max = vpmax_s16(max, max);
3913 max = vpmax_s16(max, max);
3914 return vget_lane_s16(max, 0);
3915}
3916template <>
3917EIGEN_STRONG_INLINE uint16_t predux_max<Packet4us>(const Packet4us& a) {
3918 const uint16x4_t max = vpmax_u16(a, a);
3919 return vget_lane_u16(vpmax_u16(max, max), 0);
3920}
3921template <>
3922EIGEN_STRONG_INLINE uint16_t predux_max<Packet8us>(const Packet8us& a) {
3923 uint16x4_t max = vmax_u16(vget_low_u16(a), vget_high_u16(a));
3924 max = vpmax_u16(max, max);
3925 max = vpmax_u16(max, max);
3926 return vget_lane_u16(max, 0);
3927}
3928template <>
3929EIGEN_STRONG_INLINE int32_t predux_max<Packet2i>(const Packet2i& a) {
3930 return vget_lane_s32(vpmax_s32(a, a), 0);
3931}
3932template <>
3933EIGEN_STRONG_INLINE int32_t predux_max<Packet4i>(const Packet4i& a) {
3934 const int32x2_t max = vmax_s32(vget_low_s32(a), vget_high_s32(a));
3935 return vget_lane_s32(vpmax_s32(max, max), 0);
3936}
3937template <>
3938EIGEN_STRONG_INLINE uint32_t predux_max<Packet2ui>(const Packet2ui& a) {
3939 return vget_lane_u32(vpmax_u32(a, a), 0);
3940}
3941template <>
3942EIGEN_STRONG_INLINE uint32_t predux_max<Packet4ui>(const Packet4ui& a) {
3943 const uint32x2_t max = vmax_u32(vget_low_u32(a), vget_high_u32(a));
3944 return vget_lane_u32(vpmax_u32(max, max), 0);
3945}
3946#endif
3947template <>
3948EIGEN_STRONG_INLINE int64_t predux_max<Packet2l>(const Packet2l& a) {
3949 return (std::max)(vgetq_lane_s64(a, 0), vgetq_lane_s64(a, 1));
3950}
3951template <>
3952EIGEN_STRONG_INLINE uint64_t predux_max<Packet2ul>(const Packet2ul& a) {
3953 return (std::max)(vgetq_lane_u64(a, 0), vgetq_lane_u64(a, 1));
3954}
3955
3956template <>
3957EIGEN_STRONG_INLINE bool predux_any(const Packet2f& x) {
3958 return vget_lane_u64(vreinterpret_u64_f32(x), 0) != 0;
3959}
3960
3961template <>
3962EIGEN_STRONG_INLINE bool predux_any(const Packet4f& x) {
3963 uint32x4_t u = vreinterpretq_u32_f32(x);
3964#if EIGEN_ARCH_ARM64
3965 return vget_lane_u64(vreinterpret_u64_u16(vmovn_u32(u)), 0);
3966#else
3967 uint32x2_t tmp = vorr_u32(vget_low_u32(u), vget_high_u32(u));
3968 uint32_t a, b;
3969 // GCC and Clang refuse to emit this instruction.
3970 asm("vmov %0, %1, %P2" : "=r"(a), "=r"(b) : "w"(tmp));
3971 return a | b;
3972#endif
3973}
3974
3975namespace detail {
3976// Whether any bit of a 128-bit register is set. Integer masks reduce through these bits rather than through the
3977// generic horizontal sum. On ARMv7, the 32-bit lane move after vpmax keeps predux_all's dependency chain as short as
3978// the sum's; a two-register vmov lengthens it.
3979EIGEN_STRONG_INLINE bool neon_any_bit(uint32x4_t u) {
3980#if EIGEN_ARCH_ARM64
3981 return vmaxvq_u32(u) != 0;
3982#else
3983 uint32x2_t tmp = vorr_u32(vget_low_u32(u), vget_high_u32(u));
3984 return vget_lane_u32(vpmax_u32(tmp, tmp), 0) != 0;
3985#endif
3986}
3987} // namespace detail
3988
3989template <>
3990EIGEN_STRONG_INLINE bool predux_any(const Packet4c& x) {
3991 return static_cast<int32_t>(x) != 0;
3992}
3993template <>
3994EIGEN_STRONG_INLINE bool predux_any(const Packet4uc& x) {
3995 return static_cast<uint32_t>(x) != 0;
3996}
3997template <>
3998EIGEN_STRONG_INLINE bool predux_any(const Packet8c& x) {
3999 return vget_lane_u64(vreinterpret_u64_s8(x), 0) != 0;
4000}
4001template <>
4002EIGEN_STRONG_INLINE bool predux_any(const Packet8uc& x) {
4003 return vget_lane_u64(vreinterpret_u64_u8(x), 0) != 0;
4004}
4005template <>
4006EIGEN_STRONG_INLINE bool predux_any(const Packet16c& x) {
4007 return detail::neon_any_bit(vreinterpretq_u32_s8(x));
4008}
4009template <>
4010EIGEN_STRONG_INLINE bool predux_any(const Packet16uc& x) {
4011 return detail::neon_any_bit(vreinterpretq_u32_u8(x));
4012}
4013template <>
4014EIGEN_STRONG_INLINE bool predux_any(const Packet4s& x) {
4015 return vget_lane_u64(vreinterpret_u64_s16(x), 0) != 0;
4016}
4017template <>
4018EIGEN_STRONG_INLINE bool predux_any(const Packet4us& x) {
4019 return vget_lane_u64(vreinterpret_u64_u16(x), 0) != 0;
4020}
4021template <>
4022EIGEN_STRONG_INLINE bool predux_any(const Packet8s& x) {
4023 return detail::neon_any_bit(vreinterpretq_u32_s16(x));
4024}
4025template <>
4026EIGEN_STRONG_INLINE bool predux_any(const Packet8us& x) {
4027 return detail::neon_any_bit(vreinterpretq_u32_u16(x));
4028}
4029template <>
4030EIGEN_STRONG_INLINE bool predux_any(const Packet2i& x) {
4031 return vget_lane_u64(vreinterpret_u64_s32(x), 0) != 0;
4032}
4033template <>
4034EIGEN_STRONG_INLINE bool predux_any(const Packet2ui& x) {
4035 return vget_lane_u64(vreinterpret_u64_u32(x), 0) != 0;
4036}
4037template <>
4038EIGEN_STRONG_INLINE bool predux_any(const Packet4i& x) {
4039 return detail::neon_any_bit(vreinterpretq_u32_s32(x));
4040}
4041template <>
4042EIGEN_STRONG_INLINE bool predux_any(const Packet4ui& x) {
4043 return detail::neon_any_bit(x);
4044}
4045template <>
4046EIGEN_STRONG_INLINE bool predux_any(const Packet2l& x) {
4047 return detail::neon_any_bit(vreinterpretq_u32_s64(x));
4048}
4049template <>
4050EIGEN_STRONG_INLINE bool predux_any(const Packet2ul& x) {
4051 return detail::neon_any_bit(vreinterpretq_u32_u64(x));
4052}
4053
4054// Helpers for ptranspose.
4055namespace detail {
4056
4057template <typename Packet>
4058void zip_in_place(Packet& p1, Packet& p2);
4059
4060template <>
4061EIGEN_ALWAYS_INLINE void zip_in_place<Packet2f>(Packet2f& p1, Packet2f& p2) {
4062 const float32x2x2_t tmp = vzip_f32(p1, p2);
4063 p1 = tmp.val[0];
4064 p2 = tmp.val[1];
4065}
4066
4067template <>
4068EIGEN_ALWAYS_INLINE void zip_in_place<Packet4f>(Packet4f& p1, Packet4f& p2) {
4069 const float32x4x2_t tmp = vzipq_f32(p1, p2);
4070 p1 = tmp.val[0];
4071 p2 = tmp.val[1];
4072}
4073
4074template <>
4075EIGEN_ALWAYS_INLINE void zip_in_place<Packet8c>(Packet8c& p1, Packet8c& p2) {
4076 const int8x8x2_t tmp = vzip_s8(p1, p2);
4077 p1 = tmp.val[0];
4078 p2 = tmp.val[1];
4079}
4080
4081template <>
4082EIGEN_ALWAYS_INLINE void zip_in_place<Packet16c>(Packet16c& p1, Packet16c& p2) {
4083 const int8x16x2_t tmp = vzipq_s8(p1, p2);
4084 p1 = tmp.val[0];
4085 p2 = tmp.val[1];
4086}
4087
4088template <>
4089EIGEN_ALWAYS_INLINE void zip_in_place<Packet8uc>(Packet8uc& p1, Packet8uc& p2) {
4090 const uint8x8x2_t tmp = vzip_u8(p1, p2);
4091 p1 = tmp.val[0];
4092 p2 = tmp.val[1];
4093}
4094
4095template <>
4096EIGEN_ALWAYS_INLINE void zip_in_place<Packet16uc>(Packet16uc& p1, Packet16uc& p2) {
4097 const uint8x16x2_t tmp = vzipq_u8(p1, p2);
4098 p1 = tmp.val[0];
4099 p2 = tmp.val[1];
4100}
4101
4102template <>
4103EIGEN_ALWAYS_INLINE void zip_in_place<Packet2i>(Packet2i& p1, Packet2i& p2) {
4104 const int32x2x2_t tmp = vzip_s32(p1, p2);
4105 p1 = tmp.val[0];
4106 p2 = tmp.val[1];
4107}
4108
4109template <>
4110EIGEN_ALWAYS_INLINE void zip_in_place<Packet4i>(Packet4i& p1, Packet4i& p2) {
4111 const int32x4x2_t tmp = vzipq_s32(p1, p2);
4112 p1 = tmp.val[0];
4113 p2 = tmp.val[1];
4114}
4115
4116template <>
4117EIGEN_ALWAYS_INLINE void zip_in_place<Packet2ui>(Packet2ui& p1, Packet2ui& p2) {
4118 const uint32x2x2_t tmp = vzip_u32(p1, p2);
4119 p1 = tmp.val[0];
4120 p2 = tmp.val[1];
4121}
4122
4123template <>
4124EIGEN_ALWAYS_INLINE void zip_in_place<Packet4ui>(Packet4ui& p1, Packet4ui& p2) {
4125 const uint32x4x2_t tmp = vzipq_u32(p1, p2);
4126 p1 = tmp.val[0];
4127 p2 = tmp.val[1];
4128}
4129
4130template <>
4131EIGEN_ALWAYS_INLINE void zip_in_place<Packet4s>(Packet4s& p1, Packet4s& p2) {
4132 const int16x4x2_t tmp = vzip_s16(p1, p2);
4133 p1 = tmp.val[0];
4134 p2 = tmp.val[1];
4135}
4136
4137template <>
4138EIGEN_ALWAYS_INLINE void zip_in_place<Packet8s>(Packet8s& p1, Packet8s& p2) {
4139 const int16x8x2_t tmp = vzipq_s16(p1, p2);
4140 p1 = tmp.val[0];
4141 p2 = tmp.val[1];
4142}
4143
4144template <>
4145EIGEN_ALWAYS_INLINE void zip_in_place<Packet4us>(Packet4us& p1, Packet4us& p2) {
4146 const uint16x4x2_t tmp = vzip_u16(p1, p2);
4147 p1 = tmp.val[0];
4148 p2 = tmp.val[1];
4149}
4150
4151template <>
4152EIGEN_ALWAYS_INLINE void zip_in_place<Packet8us>(Packet8us& p1, Packet8us& p2) {
4153 const uint16x8x2_t tmp = vzipq_u16(p1, p2);
4154 p1 = tmp.val[0];
4155 p2 = tmp.val[1];
4156}
4157
4158template <typename Packet>
4159EIGEN_ALWAYS_INLINE void ptranspose_impl(PacketBlock<Packet, 2>& kernel) {
4160 zip_in_place(kernel.packet[0], kernel.packet[1]);
4161}
4162
4163template <typename Packet>
4164EIGEN_ALWAYS_INLINE void ptranspose_impl(PacketBlock<Packet, 4>& kernel) {
4165 zip_in_place(kernel.packet[0], kernel.packet[2]);
4166 zip_in_place(kernel.packet[1], kernel.packet[3]);
4167 zip_in_place(kernel.packet[0], kernel.packet[1]);
4168 zip_in_place(kernel.packet[2], kernel.packet[3]);
4169}
4170
4171template <typename Packet>
4172EIGEN_ALWAYS_INLINE void ptranspose_impl(PacketBlock<Packet, 8>& kernel) {
4173 zip_in_place(kernel.packet[0], kernel.packet[4]);
4174 zip_in_place(kernel.packet[1], kernel.packet[5]);
4175 zip_in_place(kernel.packet[2], kernel.packet[6]);
4176 zip_in_place(kernel.packet[3], kernel.packet[7]);
4177
4178 zip_in_place(kernel.packet[0], kernel.packet[2]);
4179 zip_in_place(kernel.packet[1], kernel.packet[3]);
4180 zip_in_place(kernel.packet[4], kernel.packet[6]);
4181 zip_in_place(kernel.packet[5], kernel.packet[7]);
4182
4183 zip_in_place(kernel.packet[0], kernel.packet[1]);
4184 zip_in_place(kernel.packet[2], kernel.packet[3]);
4185 zip_in_place(kernel.packet[4], kernel.packet[5]);
4186 zip_in_place(kernel.packet[6], kernel.packet[7]);
4187}
4188
4189template <typename Packet>
4190EIGEN_ALWAYS_INLINE void ptranspose_impl(PacketBlock<Packet, 16>& kernel) {
4191 EIGEN_UNROLL_LOOP
4192 for (int i = 0; i < 4; ++i) {
4193 const int m = (1 << i);
4194 EIGEN_UNROLL_LOOP
4195 for (int j = 0; j < m; ++j) {
4196 const int n = (1 << (3 - i));
4197 EIGEN_UNROLL_LOOP
4198 for (int k = 0; k < n; ++k) {
4199 const int idx = 2 * j * n + k;
4200 zip_in_place(kernel.packet[idx], kernel.packet[idx + n]);
4201 }
4202 }
4203 }
4204}
4205
4206} // namespace detail
4207
4208EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet2f, 2>& kernel) {
4209 detail::ptranspose_impl(kernel);
4210}
4211EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet4f, 4>& kernel) {
4212 detail::ptranspose_impl(kernel);
4213}
4214
4215EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet4c, 4>& kernel) {
4216 const int8x8_t a = vreinterpret_s8_s32(vset_lane_s32(kernel.packet[2], vdup_n_s32(kernel.packet[0]), 1));
4217 const int8x8_t b = vreinterpret_s8_s32(vset_lane_s32(kernel.packet[3], vdup_n_s32(kernel.packet[1]), 1));
4218
4219 const int8x8x2_t zip8 = vzip_s8(a, b);
4220 const int16x4x2_t zip16 = vzip_s16(vreinterpret_s16_s8(zip8.val[0]), vreinterpret_s16_s8(zip8.val[1]));
4221
4222 kernel.packet[0] = vget_lane_s32(vreinterpret_s32_s16(zip16.val[0]), 0);
4223 kernel.packet[1] = vget_lane_s32(vreinterpret_s32_s16(zip16.val[0]), 1);
4224 kernel.packet[2] = vget_lane_s32(vreinterpret_s32_s16(zip16.val[1]), 0);
4225 kernel.packet[3] = vget_lane_s32(vreinterpret_s32_s16(zip16.val[1]), 1);
4226}
4227EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet8c, 8>& kernel) {
4228 detail::ptranspose_impl(kernel);
4229}
4230EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet8c, 4>& kernel) {
4231 detail::ptranspose_impl(kernel);
4232}
4233EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet16c, 16>& kernel) {
4234 detail::ptranspose_impl(kernel);
4235}
4236EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet16c, 8>& kernel) {
4237 detail::ptranspose_impl(kernel);
4238}
4239EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet16c, 4>& kernel) {
4240 detail::ptranspose_impl(kernel);
4241}
4242
4243EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet4uc, 4>& kernel) {
4244 const uint8x8_t a = vreinterpret_u8_u32(vset_lane_u32(kernel.packet[2], vdup_n_u32(kernel.packet[0]), 1));
4245 const uint8x8_t b = vreinterpret_u8_u32(vset_lane_u32(kernel.packet[3], vdup_n_u32(kernel.packet[1]), 1));
4246
4247 const uint8x8x2_t zip8 = vzip_u8(a, b);
4248 const uint16x4x2_t zip16 = vzip_u16(vreinterpret_u16_u8(zip8.val[0]), vreinterpret_u16_u8(zip8.val[1]));
4249
4250 kernel.packet[0] = vget_lane_u32(vreinterpret_u32_u16(zip16.val[0]), 0);
4251 kernel.packet[1] = vget_lane_u32(vreinterpret_u32_u16(zip16.val[0]), 1);
4252 kernel.packet[2] = vget_lane_u32(vreinterpret_u32_u16(zip16.val[1]), 0);
4253 kernel.packet[3] = vget_lane_u32(vreinterpret_u32_u16(zip16.val[1]), 1);
4254}
4255EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet8uc, 8>& kernel) {
4256 detail::ptranspose_impl(kernel);
4257}
4258EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet8uc, 4>& kernel) {
4259 detail::ptranspose_impl(kernel);
4260}
4261EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet16uc, 16>& kernel) {
4262 detail::ptranspose_impl(kernel);
4263}
4264EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet16uc, 8>& kernel) {
4265 detail::ptranspose_impl(kernel);
4266}
4267EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet16uc, 4>& kernel) {
4268 detail::ptranspose_impl(kernel);
4269}
4270
4271EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet4s, 4>& kernel) {
4272 detail::ptranspose_impl(kernel);
4273}
4274EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet8s, 8>& kernel) {
4275 detail::ptranspose_impl(kernel);
4276}
4277EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet8s, 4>& kernel) {
4278 detail::ptranspose_impl(kernel);
4279}
4280
4281EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet4us, 4>& kernel) {
4282 detail::ptranspose_impl(kernel);
4283}
4284EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet8us, 8>& kernel) {
4285 detail::ptranspose_impl(kernel);
4286}
4287EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet8us, 4>& kernel) {
4288 detail::ptranspose_impl(kernel);
4289}
4290
4291EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet2i, 2>& kernel) {
4292 detail::ptranspose_impl(kernel);
4293}
4294EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet4i, 4>& kernel) {
4295 detail::ptranspose_impl(kernel);
4296}
4297EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet2ui, 2>& kernel) {
4298 detail::zip_in_place(kernel.packet[0], kernel.packet[1]);
4299}
4300EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet4ui, 4>& kernel) {
4301 detail::ptranspose_impl(kernel);
4302}
4303
4304EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet2l, 2>& kernel) {
4305#if EIGEN_ARCH_ARM64
4306 const int64x2_t tmp1 = vzip1q_s64(kernel.packet[0], kernel.packet[1]);
4307 kernel.packet[1] = vzip2q_s64(kernel.packet[0], kernel.packet[1]);
4308 kernel.packet[0] = tmp1;
4309#else
4310 const int64x1_t tmp[2][2] = {{vget_low_s64(kernel.packet[0]), vget_high_s64(kernel.packet[0])},
4311 {vget_low_s64(kernel.packet[1]), vget_high_s64(kernel.packet[1])}};
4312
4313 kernel.packet[0] = vcombine_s64(tmp[0][0], tmp[1][0]);
4314 kernel.packet[1] = vcombine_s64(tmp[0][1], tmp[1][1]);
4315#endif
4316}
4317EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet2ul, 2>& kernel) {
4318#if EIGEN_ARCH_ARM64
4319 const uint64x2_t tmp1 = vzip1q_u64(kernel.packet[0], kernel.packet[1]);
4320 kernel.packet[1] = vzip2q_u64(kernel.packet[0], kernel.packet[1]);
4321 kernel.packet[0] = tmp1;
4322#else
4323 const uint64x1_t tmp[2][2] = {{vget_low_u64(kernel.packet[0]), vget_high_u64(kernel.packet[0])},
4324 {vget_low_u64(kernel.packet[1]), vget_high_u64(kernel.packet[1])}};
4325
4326 kernel.packet[0] = vcombine_u64(tmp[0][0], tmp[1][0]);
4327 kernel.packet[1] = vcombine_u64(tmp[0][1], tmp[1][1]);
4328#endif
4329}
4330
4331template <>
4332EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet2f pselect(const Packet2f& mask, const Packet2f& a, const Packet2f& b) {
4333 return vbsl_f32(vreinterpret_u32_f32(mask), a, b);
4334}
4335template <>
4336EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4f pselect(const Packet4f& mask, const Packet4f& a, const Packet4f& b) {
4337 return vbslq_f32(vreinterpretq_u32_f32(mask), a, b);
4338}
4339template <>
4340EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8c pselect(const Packet8c& mask, const Packet8c& a, const Packet8c& b) {
4341 return vbsl_s8(vreinterpret_u8_s8(mask), a, b);
4342}
4343template <>
4344EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet16c pselect(const Packet16c& mask, const Packet16c& a, const Packet16c& b) {
4345 return vbslq_s8(vreinterpretq_u8_s8(mask), a, b);
4346}
4347template <>
4348EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8uc pselect(const Packet8uc& mask, const Packet8uc& a, const Packet8uc& b) {
4349 return vbsl_u8(mask, a, b);
4350}
4351template <>
4352EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet16uc pselect(const Packet16uc& mask, const Packet16uc& a,
4353 const Packet16uc& b) {
4354 return vbslq_u8(mask, a, b);
4355}
4356template <>
4357EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4s pselect(const Packet4s& mask, const Packet4s& a, const Packet4s& b) {
4358 return vbsl_s16(vreinterpret_u16_s16(mask), a, b);
4359}
4360template <>
4361EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8s pselect(const Packet8s& mask, const Packet8s& a, const Packet8s& b) {
4362 return vbslq_s16(vreinterpretq_u16_s16(mask), a, b);
4363}
4364template <>
4365EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4us pselect(const Packet4us& mask, const Packet4us& a, const Packet4us& b) {
4366 return vbsl_u16(mask, a, b);
4367}
4368template <>
4369EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8us pselect(const Packet8us& mask, const Packet8us& a, const Packet8us& b) {
4370 return vbslq_u16(mask, a, b);
4371}
4372template <>
4373EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet2i pselect(const Packet2i& mask, const Packet2i& a, const Packet2i& b) {
4374 return vbsl_s32(vreinterpret_u32_s32(mask), a, b);
4375}
4376template <>
4377EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4i pselect(const Packet4i& mask, const Packet4i& a, const Packet4i& b) {
4378 return vbslq_s32(vreinterpretq_u32_s32(mask), a, b);
4379}
4380template <>
4381EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet2ui pselect(const Packet2ui& mask, const Packet2ui& a, const Packet2ui& b) {
4382 return vbsl_u32(mask, a, b);
4383}
4384template <>
4385EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4ui pselect(const Packet4ui& mask, const Packet4ui& a, const Packet4ui& b) {
4386 return vbslq_u32(mask, a, b);
4387}
4388template <>
4389EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet2l pselect(const Packet2l& mask, const Packet2l& a, const Packet2l& b) {
4390 return vbslq_s64(vreinterpretq_u64_s64(mask), a, b);
4391}
4392template <>
4393EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet2ul pselect(const Packet2ul& mask, const Packet2ul& a, const Packet2ul& b) {
4394 return vbslq_u64(mask, a, b);
4395}
4396
4397// Use armv8 rounding intrinsics if available.
4398#if EIGEN_ARCH_ARMV8
4399template <>
4400EIGEN_STRONG_INLINE Packet2f print<Packet2f>(const Packet2f& a) {
4401 return vrndn_f32(a);
4402}
4403
4404template <>
4405EIGEN_STRONG_INLINE Packet4f print<Packet4f>(const Packet4f& a) {
4406 return vrndnq_f32(a);
4407}
4408
4409template <>
4410EIGEN_STRONG_INLINE Packet2f pfloor<Packet2f>(const Packet2f& a) {
4411 return vrndm_f32(a);
4412}
4413
4414template <>
4415EIGEN_STRONG_INLINE Packet4f pfloor<Packet4f>(const Packet4f& a) {
4416 return vrndmq_f32(a);
4417}
4418
4419template <>
4420EIGEN_STRONG_INLINE Packet2f pceil<Packet2f>(const Packet2f& a) {
4421 return vrndp_f32(a);
4422}
4423
4424template <>
4425EIGEN_STRONG_INLINE Packet4f pceil<Packet4f>(const Packet4f& a) {
4426 return vrndpq_f32(a);
4427}
4428
4429template <>
4430EIGEN_STRONG_INLINE Packet2f pround<Packet2f>(const Packet2f& a) {
4431 return vrnda_f32(a);
4432}
4433
4434template <>
4435EIGEN_STRONG_INLINE Packet4f pround<Packet4f>(const Packet4f& a) {
4436 return vrndaq_f32(a);
4437}
4438
4439template <>
4440EIGEN_STRONG_INLINE Packet2f ptrunc<Packet2f>(const Packet2f& a) {
4441 return vrnd_f32(a);
4442}
4443
4444template <>
4445EIGEN_STRONG_INLINE Packet4f ptrunc<Packet4f>(const Packet4f& a) {
4446 return vrndq_f32(a);
4447}
4448#endif
4449
4456template <>
4457EIGEN_STRONG_INLINE Packet4uc psqrt(const Packet4uc& a) {
4458 uint8x8_t x = vreinterpret_u8_u32(vdup_n_u32(a));
4459 uint8x8_t res = vdup_n_u8(0);
4460 uint8x8_t add = vdup_n_u8(0x8);
4461 for (int i = 0; i < 4; i++) {
4462 const uint8x8_t temp = vorr_u8(res, add);
4463 res = vbsl_u8(vcge_u8(x, vmul_u8(temp, temp)), temp, res);
4464 add = vshr_n_u8(add, 1);
4465 }
4466 return vget_lane_u32(vreinterpret_u32_u8(res), 0);
4467}
4469template <>
4470EIGEN_STRONG_INLINE Packet8uc psqrt(const Packet8uc& a) {
4471 uint8x8_t res = vdup_n_u8(0);
4472 uint8x8_t add = vdup_n_u8(0x8);
4473 for (int i = 0; i < 4; i++) {
4474 const uint8x8_t temp = vorr_u8(res, add);
4475 res = vbsl_u8(vcge_u8(a, vmul_u8(temp, temp)), temp, res);
4476 add = vshr_n_u8(add, 1);
4477 }
4478 return res;
4479}
4481template <>
4482EIGEN_STRONG_INLINE Packet16uc psqrt(const Packet16uc& a) {
4483 uint8x16_t res = vdupq_n_u8(0);
4484 uint8x16_t add = vdupq_n_u8(0x8);
4485 for (int i = 0; i < 4; i++) {
4486 const uint8x16_t temp = vorrq_u8(res, add);
4487 res = vbslq_u8(vcgeq_u8(a, vmulq_u8(temp, temp)), temp, res);
4488 add = vshrq_n_u8(add, 1);
4489 }
4490 return res;
4491}
4493template <>
4494EIGEN_STRONG_INLINE Packet4us psqrt(const Packet4us& a) {
4495 uint16x4_t res = vdup_n_u16(0);
4496 uint16x4_t add = vdup_n_u16(0x80);
4497 for (int i = 0; i < 8; i++) {
4498 const uint16x4_t temp = vorr_u16(res, add);
4499 res = vbsl_u16(vcge_u16(a, vmul_u16(temp, temp)), temp, res);
4500 add = vshr_n_u16(add, 1);
4501 }
4502 return res;
4503}
4505template <>
4506EIGEN_STRONG_INLINE Packet8us psqrt(const Packet8us& a) {
4507 uint16x8_t res = vdupq_n_u16(0);
4508 uint16x8_t add = vdupq_n_u16(0x80);
4509 for (int i = 0; i < 8; i++) {
4510 const uint16x8_t temp = vorrq_u16(res, add);
4511 res = vbslq_u16(vcgeq_u16(a, vmulq_u16(temp, temp)), temp, res);
4512 add = vshrq_n_u16(add, 1);
4513 }
4514 return res;
4515}
4517template <>
4518EIGEN_STRONG_INLINE Packet2ui psqrt(const Packet2ui& a) {
4519 uint32x2_t res = vdup_n_u32(0);
4520 uint32x2_t add = vdup_n_u32(0x8000);
4521 for (int i = 0; i < 16; i++) {
4522 const uint32x2_t temp = vorr_u32(res, add);
4523 res = vbsl_u32(vcge_u32(a, vmul_u32(temp, temp)), temp, res);
4524 add = vshr_n_u32(add, 1);
4525 }
4526 return res;
4527}
4529template <>
4530EIGEN_STRONG_INLINE Packet4ui psqrt(const Packet4ui& a) {
4531 uint32x4_t res = vdupq_n_u32(0);
4532 uint32x4_t add = vdupq_n_u32(0x8000);
4533 for (int i = 0; i < 16; i++) {
4534 const uint32x4_t temp = vorrq_u32(res, add);
4535 res = vbslq_u32(vcgeq_u32(a, vmulq_u32(temp, temp)), temp, res);
4536 add = vshrq_n_u32(add, 1);
4537 }
4538 return res;
4539}
4540
4541EIGEN_STRONG_INLINE Packet4f prsqrt_float_unsafe(const Packet4f& a) {
4542 // Compute approximate reciprocal sqrt.
4543 // Does not correctly handle +/- 0 or +inf
4544 float32x4_t result = vrsqrteq_f32(a);
4545 result = vmulq_f32(vrsqrtsq_f32(vmulq_f32(a, result), result), result);
4546 result = vmulq_f32(vrsqrtsq_f32(vmulq_f32(a, result), result), result);
4547 return result;
4548}
4549
4550EIGEN_STRONG_INLINE Packet2f prsqrt_float_unsafe(const Packet2f& a) {
4551 // Compute approximate reciprocal sqrt.
4552 // Does not correctly handle +/- 0 or +inf
4553 float32x2_t result = vrsqrte_f32(a);
4554 result = vmul_f32(vrsqrts_f32(vmul_f32(a, result), result), result);
4555 result = vmul_f32(vrsqrts_f32(vmul_f32(a, result), result), result);
4556 return result;
4557}
4558
4559template <typename Packet>
4560Packet prsqrt_float_common(const Packet& a) {
4561 const Packet cst_zero = pzero(a);
4562 const Packet cst_inf = pset1<Packet>(NumTraits<float>::infinity());
4563 Packet return_zero = pcmp_eq(a, cst_inf);
4564 Packet return_inf = pcmp_eq(a, cst_zero);
4565 Packet result = prsqrt_float_unsafe(a);
4566 result = pselect(return_inf, por(cst_inf, a), result);
4567 result = pandnot(result, return_zero);
4568 return result;
4569}
4570
4571template <>
4572EIGEN_STRONG_INLINE Packet4f prsqrt(const Packet4f& a) {
4573 return prsqrt_float_common(a);
4574}
4575
4576template <>
4577EIGEN_STRONG_INLINE Packet2f prsqrt(const Packet2f& a) {
4578 return prsqrt_float_common(a);
4579}
4580
4581template <>
4582EIGEN_STRONG_INLINE Packet4f preciprocal<Packet4f>(const Packet4f& a) {
4583 // Compute approximate reciprocal.
4584 const float32x4_t estimate = vrecpeq_f32(a);
4585 float32x4_t result = vmulq_f32(vrecpsq_f32(a, estimate), estimate);
4586 result = vmulq_f32(vrecpsq_f32(a, result), result);
4587 // 1 / a has the sign of a. The estimate is +-inf for |a| < 2^-128, which the steps turn into -+inf.
4588 return vbslq_f32(vdupq_n_u32(0x80000000u), a, result);
4589}
4590
4591template <>
4592EIGEN_STRONG_INLINE Packet2f preciprocal<Packet2f>(const Packet2f& a) {
4593 // Compute approximate reciprocal.
4594 const float32x2_t estimate = vrecpe_f32(a);
4595 float32x2_t result = vmul_f32(vrecps_f32(a, estimate), estimate);
4596 result = vmul_f32(vrecps_f32(a, result), result);
4597 // 1 / a has the sign of a. The estimate is +-inf for |a| < 2^-128, which the steps turn into -+inf.
4598 return vbsl_f32(vdup_n_u32(0x80000000u), a, result);
4599}
4600
4601// Unfortunately vsqrt_f32 is only available for A64.
4602#if EIGEN_ARCH_ARM64
4603template <>
4604EIGEN_STRONG_INLINE Packet4f psqrt(const Packet4f& a) {
4605 return vsqrtq_f32(a);
4606}
4607
4608template <>
4609EIGEN_STRONG_INLINE Packet2f psqrt(const Packet2f& a) {
4610 return vsqrt_f32(a);
4611}
4612
4613template <>
4614EIGEN_STRONG_INLINE Packet4f pdiv(const Packet4f& a, const Packet4f& b) {
4615 return vdivq_f32(a, b);
4616}
4617
4618template <>
4619EIGEN_STRONG_INLINE Packet2f pdiv(const Packet2f& a, const Packet2f& b) {
4620 return vdiv_f32(a, b);
4621}
4622#else
4623template <typename Packet>
4624EIGEN_STRONG_INLINE Packet psqrt_float_common(const Packet& a) {
4625 const Packet cst_zero = pzero(a);
4626 const Packet cst_inf = pset1<Packet>(NumTraits<float>::infinity());
4627
4628 Packet result = pmul(a, prsqrt_float_unsafe(a));
4629 Packet a_is_zero = pcmp_eq(a, cst_zero);
4630 Packet a_is_inf = pcmp_eq(a, cst_inf);
4631 Packet return_a = por(a_is_zero, a_is_inf);
4632
4633 result = pselect(return_a, a, result);
4634 return result;
4635}
4636
4637template <>
4638EIGEN_STRONG_INLINE Packet4f psqrt(const Packet4f& a) {
4639 return psqrt_float_common(a);
4640}
4641
4642template <>
4643EIGEN_STRONG_INLINE Packet2f psqrt(const Packet2f& a) {
4644 return psqrt_float_common(a);
4645}
4646
4647template <typename Packet>
4648EIGEN_STRONG_INLINE Packet pdiv_float_common(const Packet& a, const Packet& b) {
4649 // if b is large, NEON intrinsics will flush preciprocal(b) to zero
4650 // avoid underflow with the following manipulation:
4651 // a / b = f * (a * reciprocal(f * b))
4652
4653 const Packet cst_one = pset1<Packet>(1.0f);
4654 const Packet cst_quarter = pset1<Packet>(0.25f);
4655 const Packet cst_thresh = pset1<Packet>(NumTraits<float>::highest() / 4.0f);
4656
4657 Packet b_will_underflow = pcmp_le(cst_thresh, pabs(b));
4658 Packet f = pselect(b_will_underflow, cst_quarter, cst_one);
4659 Packet result = pmul(f, pmul(a, preciprocal(pmul(b, f))));
4660 return result;
4661}
4662
4663template <>
4664EIGEN_STRONG_INLINE Packet4f pdiv<Packet4f>(const Packet4f& a, const Packet4f& b) {
4665 return pdiv_float_common(a, b);
4666}
4667
4668template <>
4669EIGEN_STRONG_INLINE Packet2f pdiv<Packet2f>(const Packet2f& a, const Packet2f& b) {
4670 return pdiv_float_common(a, b);
4671}
4672#endif
4673
4674//---------- bfloat16 ----------
4675// TODO: Add support for native armv8.6-a bfloat16_t
4676
4677// TODO: Guard if we have native bfloat16 support
4678typedef eigen_packet_wrapper<uint16x4_t, 19> Packet4bf;
4679
4680template <>
4681struct is_arithmetic<Packet4bf> : std::true_type {};
4682
4683template <>
4684struct packet_traits<bfloat16> : default_packet_traits {
4685 typedef Packet4bf type;
4686 typedef Packet4bf half;
4687 enum {
4688 Vectorizable = 1,
4689 AlignedOnScalar = 1,
4690 size = 4,
4691
4692 HasCmp = 1,
4693 HasAdd = 1,
4694 HasSub = 1,
4695 HasShift = 1,
4696 HasMul = 1,
4697 HasNegate = 1,
4698 HasAbs = 1,
4699 HasArg = 0,
4700 HasAbsDiff = 1,
4701 HasMin = 1,
4702 HasMax = 1,
4703 HasConj = 1,
4704 HasSetLinear = 1,
4705 HasDiv = 1,
4706 HasSin = EIGEN_FAST_MATH,
4707 HasCos = EIGEN_FAST_MATH,
4708 HasLog = 1,
4709 HasExp = 1,
4710 HasSqrt = 0,
4711 HasTanh = EIGEN_FAST_MATH,
4712 HasErf = EIGEN_FAST_MATH,
4713 HasBessel = 0, // Issues with accuracy.
4714 HasNdtri = 0
4715 };
4716};
4717
4718template <>
4719struct unpacket_traits<Packet4bf> : neon_unpacket_default<Packet4bf, bfloat16> {};
4720
4721namespace detail {
4722template <>
4723EIGEN_ALWAYS_INLINE void zip_in_place<Packet4bf>(Packet4bf& p1, Packet4bf& p2) {
4724 const uint16x4x2_t tmp = vzip_u16(p1, p2);
4725 p1 = tmp.val[0];
4726 p2 = tmp.val[1];
4727}
4728} // namespace detail
4729
4730EIGEN_STRONG_INLINE Packet4bf F32ToBf16(const Packet4f& p) {
4731 // See the scalar implementation in BFloat16.h for a comprehensible explanation
4732 // of this fast rounding algorithm
4733 Packet4ui input = Packet4ui(vreinterpretq_u32_f32(p));
4734
4735 // lsb = (input >> 16) & 1
4736 Packet4ui lsb = vandq_u32(vshrq_n_u32(input, 16), vdupq_n_u32(1));
4737
4738 // rounding_bias = 0x7fff + lsb
4739 Packet4ui rounding_bias = vaddq_u32(lsb, vdupq_n_u32(0x7fff));
4740
4741 // input += rounding_bias
4742 input = vaddq_u32(input, rounding_bias);
4743
4744 // input = input >> 16
4745 input = vshrq_n_u32(input, 16);
4746
4747 // Replace float-nans by bfloat16-nans, that is 0x7fc0
4748 const Packet4ui bf16_nan = vdupq_n_u32(0x7fc0);
4749 const Packet4ui mask = vceqq_f32(p, p);
4750 input = vbslq_u32(mask, input, bf16_nan);
4751
4752 // output = static_cast<uint16_t>(input)
4753 return vmovn_u32(input);
4754}
4755
4756// Discard the low 16 bits of each float. Only valid when every lane already holds an exact
4757// bfloat16 value, in which case this agrees with F32ToBf16 but skips its rounding and NaN
4758// canonicalization. pmin/pmax qualify: they return one of their operands bit for bit.
4759EIGEN_STRONG_INLINE Packet4bf F32ToBf16Truncate(const Packet4f& p) { return vshrn_n_u32(vreinterpretq_u32_f32(p), 16); }
4760
4761EIGEN_STRONG_INLINE Packet4f Bf16ToF32(const Packet4bf& p) {
4762 return Packet4f(vreinterpretq_f32_u32(vshlq_n_u32(vmovl_u16(p), 16)));
4763}
4764
4765EIGEN_STRONG_INLINE Packet4bf F32MaskToBf16Mask(const Packet4f& p) { return vmovn_u32(vreinterpretq_u32_f32(p)); }
4766
4767template <>
4768EIGEN_STRONG_INLINE Packet4bf pset1<Packet4bf>(const bfloat16& from) {
4769 return Packet4bf(pset1<Packet4us>(from.value));
4770}
4771
4772template <>
4773EIGEN_STRONG_INLINE bfloat16 pfirst<Packet4bf>(const Packet4bf& from) {
4774 return bfloat16_impl::raw_uint16_to_bfloat16(static_cast<uint16_t>(pfirst<Packet4us>(Packet4us(from))));
4775}
4776
4777template <>
4778EIGEN_STRONG_INLINE Packet4bf pload<Packet4bf>(const bfloat16* from) {
4779 return Packet4bf(
4780 pload<Packet4us>(reinterpret_cast<const uint16_t*>(assume_aligned<unpacket_traits<Packet4bf>::alignment>(from))));
4781}
4782
4783template <>
4784EIGEN_STRONG_INLINE Packet4bf ploadu<Packet4bf>(const bfloat16* from) {
4785 return Packet4bf(ploadu<Packet4us>(reinterpret_cast<const uint16_t*>(from)));
4786}
4787
4788template <>
4789EIGEN_STRONG_INLINE void pstore<bfloat16>(bfloat16* to, const Packet4bf& from) {
4790 EIGEN_DEBUG_ALIGNED_STORE vst1_u16(
4791 reinterpret_cast<uint16_t*>(assume_aligned<unpacket_traits<Packet4bf>::alignment>(to)), from);
4792}
4793
4794template <>
4795EIGEN_STRONG_INLINE void pstoreu<bfloat16>(bfloat16* to, const Packet4bf& from) {
4796 EIGEN_DEBUG_UNALIGNED_STORE vst1_u16(reinterpret_cast<uint16_t*>(to), from);
4797}
4798
4799template <>
4800EIGEN_STRONG_INLINE Packet4bf ploaddup<Packet4bf>(const bfloat16* from) {
4801 return Packet4bf(ploaddup<Packet4us>(reinterpret_cast<const uint16_t*>(from)));
4802}
4803
4804template <>
4805EIGEN_STRONG_INLINE Packet4bf pabs(const Packet4bf& a) {
4806 return Packet4bf(vand_u16(a, vdup_n_u16(0x7fff)));
4807}
4808
4809template <>
4810EIGEN_STRONG_INLINE Packet4bf pmin<PropagateNumbers, Packet4bf>(const Packet4bf& a, const Packet4bf& b) {
4811 return F32ToBf16Truncate(pmin<PropagateNumbers, Packet4f>(Bf16ToF32(a), Bf16ToF32(b)));
4812}
4813template <>
4814EIGEN_STRONG_INLINE Packet4bf pmin<PropagateNaN, Packet4bf>(const Packet4bf& a, const Packet4bf& b) {
4815 return F32ToBf16Truncate(pmin<PropagateNaN, Packet4f>(Bf16ToF32(a), Bf16ToF32(b)));
4816}
4817
4818template <>
4819EIGEN_STRONG_INLINE Packet4bf pmin<Packet4bf>(const Packet4bf& a, const Packet4bf& b) {
4820 return F32ToBf16Truncate(pmin<Packet4f>(Bf16ToF32(a), Bf16ToF32(b)));
4821}
4822
4823template <>
4824EIGEN_STRONG_INLINE Packet4bf pmax<PropagateNumbers, Packet4bf>(const Packet4bf& a, const Packet4bf& b) {
4825 return F32ToBf16Truncate(pmax<PropagateNumbers, Packet4f>(Bf16ToF32(a), Bf16ToF32(b)));
4826}
4827template <>
4828EIGEN_STRONG_INLINE Packet4bf pmax<PropagateNaN, Packet4bf>(const Packet4bf& a, const Packet4bf& b) {
4829 return F32ToBf16Truncate(pmax<PropagateNaN, Packet4f>(Bf16ToF32(a), Bf16ToF32(b)));
4830}
4831
4832template <>
4833EIGEN_STRONG_INLINE Packet4bf pmax<Packet4bf>(const Packet4bf& a, const Packet4bf& b) {
4834 return F32ToBf16Truncate(pmax<Packet4f>(Bf16ToF32(a), Bf16ToF32(b)));
4835}
4836
4837template <>
4838EIGEN_STRONG_INLINE Packet4bf plset<Packet4bf>(const bfloat16& a) {
4839 return F32ToBf16(plset<Packet4f>(static_cast<float>(a)));
4840}
4841
4842template <>
4843EIGEN_STRONG_INLINE Packet4bf por(const Packet4bf& a, const Packet4bf& b) {
4844 return Packet4bf(por<Packet4us>(Packet4us(a), Packet4us(b)));
4845}
4846
4847template <>
4848EIGEN_STRONG_INLINE Packet4bf pxor(const Packet4bf& a, const Packet4bf& b) {
4849 return Packet4bf(pxor<Packet4us>(Packet4us(a), Packet4us(b)));
4850}
4851
4852template <>
4853EIGEN_STRONG_INLINE Packet4bf pand(const Packet4bf& a, const Packet4bf& b) {
4854 return Packet4bf(pand<Packet4us>(Packet4us(a), Packet4us(b)));
4855}
4856
4857template <>
4858EIGEN_STRONG_INLINE Packet4bf pandnot(const Packet4bf& a, const Packet4bf& b) {
4859 return Packet4bf(pandnot<Packet4us>(Packet4us(a), Packet4us(b)));
4860}
4861
4862template <>
4863EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4bf pselect(const Packet4bf& mask, const Packet4bf& a, const Packet4bf& b) {
4864 return Packet4bf(pselect<Packet4us>(Packet4us(mask), Packet4us(a), Packet4us(b)));
4865}
4866
4867template <>
4868EIGEN_STRONG_INLINE Packet4bf print<Packet4bf>(const Packet4bf& a) {
4869 return F32ToBf16Truncate(print<Packet4f>(Bf16ToF32(a)));
4870}
4871
4872template <>
4873EIGEN_STRONG_INLINE Packet4bf pfloor<Packet4bf>(const Packet4bf& a) {
4874 return F32ToBf16Truncate(pfloor<Packet4f>(Bf16ToF32(a)));
4875}
4876
4877template <>
4878EIGEN_STRONG_INLINE Packet4bf pceil<Packet4bf>(const Packet4bf& a) {
4879 return F32ToBf16Truncate(pceil<Packet4f>(Bf16ToF32(a)));
4880}
4881
4882template <>
4883EIGEN_STRONG_INLINE Packet4bf pround<Packet4bf>(const Packet4bf& a) {
4884 return F32ToBf16Truncate(pround<Packet4f>(Bf16ToF32(a)));
4885}
4886
4887template <>
4888EIGEN_STRONG_INLINE Packet4bf ptrunc<Packet4bf>(const Packet4bf& a) {
4889 return F32ToBf16Truncate(ptrunc<Packet4f>(Bf16ToF32(a)));
4890}
4891
4892template <>
4893EIGEN_STRONG_INLINE Packet4bf padd<Packet4bf>(const Packet4bf& a, const Packet4bf& b) {
4894 return F32ToBf16(padd<Packet4f>(Bf16ToF32(a), Bf16ToF32(b)));
4895}
4896
4897template <>
4898EIGEN_STRONG_INLINE Packet4bf psub<Packet4bf>(const Packet4bf& a, const Packet4bf& b) {
4899 return F32ToBf16(psub<Packet4f>(Bf16ToF32(a), Bf16ToF32(b)));
4900}
4901
4902template <>
4903EIGEN_STRONG_INLINE Packet4bf pmul<Packet4bf>(const Packet4bf& a, const Packet4bf& b) {
4904 return F32ToBf16(pmul<Packet4f>(Bf16ToF32(a), Bf16ToF32(b)));
4905}
4906
4907template <>
4908EIGEN_STRONG_INLINE Packet4bf pmadd<Packet4bf>(const Packet4bf& a, const Packet4bf& b, const Packet4bf& c) {
4909 return F32ToBf16(pmadd<Packet4f>(Bf16ToF32(a), Bf16ToF32(b), Bf16ToF32(c)));
4910}
4911
4912template <>
4913EIGEN_STRONG_INLINE Packet4bf pmsub<Packet4bf>(const Packet4bf& a, const Packet4bf& b, const Packet4bf& c) {
4914 return F32ToBf16(pmsub<Packet4f>(Bf16ToF32(a), Bf16ToF32(b), Bf16ToF32(c)));
4915}
4916
4917template <>
4918EIGEN_STRONG_INLINE Packet4bf pnmadd<Packet4bf>(const Packet4bf& a, const Packet4bf& b, const Packet4bf& c) {
4919 return F32ToBf16(pnmadd<Packet4f>(Bf16ToF32(a), Bf16ToF32(b), Bf16ToF32(c)));
4920}
4921
4922template <>
4923EIGEN_STRONG_INLINE Packet4bf pnmsub<Packet4bf>(const Packet4bf& a, const Packet4bf& b, const Packet4bf& c) {
4924 return F32ToBf16(pnmsub<Packet4f>(Bf16ToF32(a), Bf16ToF32(b), Bf16ToF32(c)));
4925}
4926
4927template <>
4928EIGEN_STRONG_INLINE Packet4bf pdiv<Packet4bf>(const Packet4bf& a, const Packet4bf& b) {
4929 return F32ToBf16(pdiv<Packet4f>(Bf16ToF32(a), Bf16ToF32(b)));
4930}
4931
4932template <>
4933EIGEN_STRONG_INLINE Packet4bf pgather<bfloat16, Packet4bf>(const bfloat16* from, Index stride) {
4934 return Packet4bf(pgather<uint16_t, Packet4us>(reinterpret_cast<const uint16_t*>(from), stride));
4935}
4936
4937template <>
4938EIGEN_STRONG_INLINE void pscatter<bfloat16, Packet4bf>(bfloat16* to, const Packet4bf& from, Index stride) {
4939 pscatter<uint16_t, Packet4us>(reinterpret_cast<uint16_t*>(to), Packet4us(from), stride);
4940}
4941
4942template <>
4943EIGEN_STRONG_INLINE bfloat16 predux<Packet4bf>(const Packet4bf& a) {
4944 return static_cast<bfloat16>(predux<Packet4f>(Bf16ToF32(a)));
4945}
4946
4947template <>
4948EIGEN_STRONG_INLINE bfloat16 predux_max<Packet4bf>(const Packet4bf& a) {
4949 return bfloat16_impl::exact_float_to_bfloat16(predux_max<Packet4f>(Bf16ToF32(a)));
4950}
4951
4952template <>
4953EIGEN_STRONG_INLINE bfloat16 predux_min<Packet4bf>(const Packet4bf& a) {
4954 return bfloat16_impl::exact_float_to_bfloat16(predux_min<Packet4f>(Bf16ToF32(a)));
4955}
4956
4957template <>
4958EIGEN_STRONG_INLINE bfloat16 predux_mul<Packet4bf>(const Packet4bf& a) {
4959 return static_cast<bfloat16>(predux_mul<Packet4f>(Bf16ToF32(a)));
4960}
4961
4962template <>
4963EIGEN_STRONG_INLINE bool predux_any(const Packet4bf& a) {
4964 return vget_lane_u64(vreinterpret_u64_u16(Packet4us(a)), 0) != 0;
4965}
4966
4967template <>
4968EIGEN_STRONG_INLINE Packet4bf preverse<Packet4bf>(const Packet4bf& a) {
4969 return Packet4bf(preverse<Packet4us>(Packet4us(a)));
4970}
4971
4972EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet4bf, 4>& kernel) {
4973 detail::ptranspose_impl(kernel);
4974}
4975
4976template <>
4977EIGEN_STRONG_INLINE Packet4bf pabsdiff<Packet4bf>(const Packet4bf& a, const Packet4bf& b) {
4978 return F32ToBf16(pabsdiff<Packet4f>(Bf16ToF32(a), Bf16ToF32(b)));
4979}
4980
4981template <>
4982EIGEN_STRONG_INLINE Packet4bf pcmp_eq<Packet4bf>(const Packet4bf& a, const Packet4bf& b) {
4983 return F32MaskToBf16Mask(pcmp_eq<Packet4f>(Bf16ToF32(a), Bf16ToF32(b)));
4984}
4985
4986template <>
4987EIGEN_STRONG_INLINE Packet4bf pcmp_lt<Packet4bf>(const Packet4bf& a, const Packet4bf& b) {
4988 return F32MaskToBf16Mask(pcmp_lt<Packet4f>(Bf16ToF32(a), Bf16ToF32(b)));
4989}
4990
4991template <>
4992EIGEN_STRONG_INLINE Packet4bf pcmp_lt_or_nan<Packet4bf>(const Packet4bf& a, const Packet4bf& b) {
4993 return F32MaskToBf16Mask(pcmp_lt_or_nan<Packet4f>(Bf16ToF32(a), Bf16ToF32(b)));
4994}
4995
4996// Classify on the raw bits, as the scalar isinf/isnan/isfinite do: |a| ==, >, < 0x7f80.
4997template <>
4998EIGEN_STRONG_INLINE Packet4bf pisinf<Packet4bf>(const Packet4bf& a) {
4999 constexpr uint16_t kInf = ((1 << 8) - 1) << 7;
5000 constexpr uint16_t kAbsMask = (1 << 15) - 1;
5001 return vceq_u16(vand_u16(a, vdup_n_u16(kAbsMask)), vdup_n_u16(kInf));
5002}
5003
5004template <>
5005EIGEN_STRONG_INLINE Packet4bf pisnan<Packet4bf>(const Packet4bf& a) {
5006 constexpr uint16_t kInf = ((1 << 8) - 1) << 7;
5007 constexpr uint16_t kAbsMask = (1 << 15) - 1;
5008 return vcgt_u16(vand_u16(a, vdup_n_u16(kAbsMask)), vdup_n_u16(kInf));
5009}
5010
5011// Compare encoded lanes: widening bf16 subnormals to float loses them under DAZ/FZ.
5012template <>
5013EIGEN_STRONG_INLINE Packet4bf psign<Packet4bf>(const Packet4bf& a) {
5014 const uint16x4_t abs_mask = vdup_n_u16(0x7fff);
5015 const uint16x4_t is_nan = vcgt_u16(vand_u16(a, abs_mask), vdup_n_u16(0x7f80));
5016 const uint16x4_t keep = vorr_u16(is_nan, vdup_n_u16(0x8000));
5017 return vand_u16(vbsl_u16(keep, a, vdup_n_u16(0x3f80)), vtst_u16(a, abs_mask));
5018}
5019
5020template <>
5021EIGEN_STRONG_INLINE Packet4bf pisfinite<Packet4bf>(const Packet4bf& a) {
5022 constexpr uint16_t kInf = ((1 << 8) - 1) << 7;
5023 constexpr uint16_t kAbsMask = (1 << 15) - 1;
5024 return vclt_u16(vand_u16(a, vdup_n_u16(kAbsMask)), vdup_n_u16(kInf));
5025}
5026
5027template <>
5028EIGEN_STRONG_INLINE Packet4bf pcmp_le<Packet4bf>(const Packet4bf& a, const Packet4bf& b) {
5029 return F32MaskToBf16Mask(pcmp_le<Packet4f>(Bf16ToF32(a), Bf16ToF32(b)));
5030}
5031
5032template <>
5033EIGEN_STRONG_INLINE Packet4bf pnegate<Packet4bf>(const Packet4bf& a) {
5034 return Packet4bf(pxor<Packet4us>(Packet4us(a), pset1<Packet4us>(static_cast<uint16_t>(0x8000))));
5035}
5036
5037//---------- double ----------
5038
5039#if EIGEN_ARCH_ARM64
5040
5041#if EIGEN_COMP_GNUC
5042// Bug 907: workaround missing declarations of the following two functions in the ADK
5043// Defining these functions as templates ensures that if these intrinsics are
5044// already defined in arm_neon.h, then our workaround doesn't cause a conflict
5045// and has lower priority in overload resolution.
5046// This doesn't work with MSVC though, since the function names are macros.
5047template <typename T>
5048uint64x2_t vreinterpretq_u64_f64(T a) {
5049 return (uint64x2_t)a;
5050}
5051
5052template <typename T>
5053float64x2_t vreinterpretq_f64_u64(T a) {
5054 return (float64x2_t)a;
5055}
5056#endif
5057
5058#if EIGEN_COMP_MSVC_STRICT
5059typedef eigen_packet_wrapper<float64x2_t, 18> Packet2d;
5060typedef eigen_packet_wrapper<float64x1_t, 19> Packet1d;
5061
5062EIGEN_ALWAYS_INLINE Packet2d make_packet2d(double a, double b) {
5063 double from[2] = {a, b};
5064 return vld1q_f64(from);
5065}
5066
5067#else
5068typedef float64x2_t Packet2d;
5069typedef float64x1_t Packet1d;
5070
5071EIGEN_ALWAYS_INLINE Packet2d make_packet2d(double a, double b) { return Packet2d{a, b}; }
5072#endif
5073
5074// functionally equivalent to _mm_shuffle_pd in SSE (i.e. shuffle(m, n, mask) equals _mm_shuffle_pd(m,n,mask))
5075// Currently used in LU/arch/InverseSize4.h to enable a shared implementation
5076// for fast inversion of matrices of size 4.
5077EIGEN_STRONG_INLINE Packet2d shuffle(const Packet2d& m, const Packet2d& n, int mask) {
5078 const double* a = reinterpret_cast<const double*>(&m);
5079 const double* b = reinterpret_cast<const double*>(&n);
5080 Packet2d res = make_packet2d(*(a + (mask & 1)), *(b + ((mask >> 1) & 1)));
5081 return res;
5082}
5083
5084EIGEN_STRONG_INLINE Packet2d vec2d_swizzle2(const Packet2d& a, const Packet2d& b, int mask) {
5085 return shuffle(a, b, mask);
5086}
5087EIGEN_STRONG_INLINE Packet2d vec2d_unpacklo(const Packet2d& a, const Packet2d& b) { return shuffle(a, b, 0); }
5088EIGEN_STRONG_INLINE Packet2d vec2d_unpackhi(const Packet2d& a, const Packet2d& b) { return shuffle(a, b, 3); }
5089#define vec2d_duplane(a, p) Packet2d(vdupq_laneq_f64(a, p))
5090
5091template <>
5092struct packet_traits<double> : default_packet_traits {
5093 typedef Packet2d type;
5094 typedef Packet2d half;
5095 enum {
5096 Vectorizable = 1,
5097 AlignedOnScalar = 1,
5098 size = 2,
5099
5100 HasCmp = 1,
5101 HasAdd = 1,
5102 HasSub = 1,
5103 HasShift = 1,
5104 HasMul = 1,
5105 HasNegate = 1,
5106 HasAbs = 1,
5107 HasArg = 0,
5108 HasAbsDiff = 1,
5109 HasMin = 1,
5110 HasMax = 1,
5111 HasConj = 1,
5112 HasSetLinear = 1,
5113
5114 HasDiv = 1,
5115
5116#if EIGEN_ARCH_ARM64
5117 HasExp = 1,
5118 HasLog = 1,
5119 HasLog10 = 1,
5120 HasLog1p = 1,
5121 HasExpm1 = 1,
5122 HasPow = 1,
5123 HasATan = 1,
5124 HasATanh = 1,
5125 HasSinh = 1,
5126 HasCosh = 1,
5127 HasASinh = 1,
5128 HasACosh = 1,
5129#endif
5130 HasSin = EIGEN_FAST_MATH,
5131 HasCos = EIGEN_FAST_MATH,
5132 HasTan = EIGEN_FAST_MATH,
5133 HasSqrt = 1,
5134 HasRsqrt = 1,
5135 HasCbrt = 1,
5136 HasTanh = EIGEN_FAST_MATH,
5137 HasErf = EIGEN_FAST_MATH,
5138 HasErfc = EIGEN_FAST_MATH
5139 };
5140};
5141
5142template <>
5143struct unpacket_traits<Packet2d> : neon_unpacket_default<Packet2d, double> {
5144 using integer_packet = Packet2l;
5145};
5146
5147template <>
5148EIGEN_STRONG_INLINE Packet2d pzero<Packet2d>(const Packet2d& /*a*/) {
5149 return vdupq_n_f64(0.0);
5150}
5151
5152template <>
5153EIGEN_STRONG_INLINE Packet2d pset1<Packet2d>(const double& from) {
5154 return vdupq_n_f64(from);
5155}
5156
5157template <>
5158EIGEN_STRONG_INLINE Packet2d plset<Packet2d>(const double& a) {
5159 const double c[] = {0.0, 1.0};
5160 return vaddq_f64(pset1<Packet2d>(a), vld1q_f64(c));
5161}
5162
5163template <>
5164EIGEN_STRONG_INLINE Packet2d padd<Packet2d>(const Packet2d& a, const Packet2d& b) {
5165 return vaddq_f64(a, b);
5166}
5167
5168template <>
5169EIGEN_STRONG_INLINE Packet2d psub<Packet2d>(const Packet2d& a, const Packet2d& b) {
5170 return vsubq_f64(a, b);
5171}
5172
5173template <>
5174EIGEN_STRONG_INLINE Packet2d pxor<Packet2d>(const Packet2d&, const Packet2d&);
5175template <>
5176EIGEN_STRONG_INLINE Packet2d paddsub<Packet2d>(const Packet2d& a, const Packet2d& b) {
5177 const Packet2d mask = make_packet2d(numext::bit_cast<double>(0x8000000000000000ull), 0.0);
5178 return padd(a, pxor(mask, b));
5179}
5180
5181template <>
5182EIGEN_STRONG_INLINE Packet2d pnegate(const Packet2d& a) {
5183 return vnegq_f64(a);
5184}
5185
5186template <>
5187EIGEN_STRONG_INLINE Packet2d pmul<Packet2d>(const Packet2d& a, const Packet2d& b) {
5188 return vmulq_f64(a, b);
5189}
5190
5191template <>
5192EIGEN_STRONG_INLINE Packet2d pdiv<Packet2d>(const Packet2d& a, const Packet2d& b) {
5193 return vdivq_f64(a, b);
5194}
5195
5196#ifdef EIGEN_VECTORIZE_FMA
5197// See bug 936. See above comment about FMA for float.
5198template <>
5199EIGEN_STRONG_INLINE Packet2d pmadd(const Packet2d& a, const Packet2d& b, const Packet2d& c) {
5200 return vfmaq_f64(c, a, b);
5201}
5202template <>
5203EIGEN_STRONG_INLINE Packet2d pnmadd(const Packet2d& a, const Packet2d& b, const Packet2d& c) {
5204 return vfmsq_f64(c, a, b);
5205}
5206#else
5207template <>
5208EIGEN_STRONG_INLINE Packet2d pmadd(const Packet2d& a, const Packet2d& b, const Packet2d& c) {
5209 return vmlaq_f64(c, a, b);
5210}
5211template <>
5212EIGEN_STRONG_INLINE Packet2d pnmadd(const Packet2d& a, const Packet2d& b, const Packet2d& c) {
5213 return vmlsq_f64(c, a, b);
5214}
5215#endif
5216template <>
5217EIGEN_STRONG_INLINE Packet2d pmsub(const Packet2d& a, const Packet2d& b, const Packet2d& c) {
5218 return pnegate(pnmadd(a, b, c));
5219}
5220template <>
5221EIGEN_STRONG_INLINE Packet2d pnmsub(const Packet2d& a, const Packet2d& b, const Packet2d& c) {
5222 return pnegate(pmadd(a, b, c));
5223}
5224template <>
5225EIGEN_STRONG_INLINE Packet2d pmin<Packet2d>(const Packet2d& a, const Packet2d& b) {
5226 return vminq_f64(a, b);
5227}
5228
5229#ifdef __ARM_FEATURE_NUMERIC_MAXMIN
5230// numeric max and min are only available if ARM_FEATURE_NUMERIC_MAXMIN is defined (which can only be the case for Armv8
5231// systems).
5232template <>
5233EIGEN_STRONG_INLINE Packet2d pmin<PropagateNumbers, Packet2d>(const Packet2d& a, const Packet2d& b) {
5234 return vminnmq_f64(a, b);
5235}
5236template <>
5237EIGEN_STRONG_INLINE Packet2d pmax<PropagateNumbers, Packet2d>(const Packet2d& a, const Packet2d& b) {
5238 return vmaxnmq_f64(a, b);
5239}
5240
5241#endif
5242
5243template <>
5244struct pminmax_propagates_nan<Packet2d> : bool_constant<true> {};
5245
5246template <>
5247EIGEN_STRONG_INLINE Packet2d pmax<Packet2d>(const Packet2d& a, const Packet2d& b) {
5248 return vmaxq_f64(a, b);
5249}
5250
5251// Logical Operations are not supported for float, so we have to reinterpret casts using NEON intrinsics
5252template <>
5253EIGEN_STRONG_INLINE Packet2d pand<Packet2d>(const Packet2d& a, const Packet2d& b) {
5254 return vreinterpretq_f64_u64(vandq_u64(vreinterpretq_u64_f64(a), vreinterpretq_u64_f64(b)));
5255}
5256
5257template <>
5258EIGEN_STRONG_INLINE Packet2d por<Packet2d>(const Packet2d& a, const Packet2d& b) {
5259 return vreinterpretq_f64_u64(vorrq_u64(vreinterpretq_u64_f64(a), vreinterpretq_u64_f64(b)));
5260}
5261
5262template <>
5263EIGEN_STRONG_INLINE Packet2d pxor<Packet2d>(const Packet2d& a, const Packet2d& b) {
5264 return vreinterpretq_f64_u64(veorq_u64(vreinterpretq_u64_f64(a), vreinterpretq_u64_f64(b)));
5265}
5266
5267template <>
5268EIGEN_STRONG_INLINE Packet2d pandnot<Packet2d>(const Packet2d& a, const Packet2d& b) {
5269 return vreinterpretq_f64_u64(vbicq_u64(vreinterpretq_u64_f64(a), vreinterpretq_u64_f64(b)));
5270}
5271
5272template <>
5273EIGEN_STRONG_INLINE Packet2d pcmp_le(const Packet2d& a, const Packet2d& b) {
5274 return vreinterpretq_f64_u64(vcleq_f64(a, b));
5275}
5276
5277template <>
5278EIGEN_STRONG_INLINE Packet2d pcmp_lt(const Packet2d& a, const Packet2d& b) {
5279 return vreinterpretq_f64_u64(vcltq_f64(a, b));
5280}
5281
5282template <>
5283EIGEN_STRONG_INLINE Packet2d pcmp_lt_or_nan(const Packet2d& a, const Packet2d& b) {
5284 return vreinterpretq_f64_u32(vmvnq_u32(vreinterpretq_u32_u64(vcgeq_f64(a, b))));
5285}
5286
5287template <>
5288EIGEN_STRONG_INLINE Packet2d pcmp_eq(const Packet2d& a, const Packet2d& b) {
5289 return vreinterpretq_f64_u64(vceqq_f64(a, b));
5290}
5291
5292template <>
5293EIGEN_STRONG_INLINE Packet2d pload<Packet2d>(const double* from) {
5294 EIGEN_DEBUG_ALIGNED_LOAD return vld1q_f64(assume_aligned<unpacket_traits<Packet2d>::alignment>(from));
5295}
5296
5297template <>
5298EIGEN_STRONG_INLINE Packet2d ploadu<Packet2d>(const double* from) {
5299 EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_f64(from);
5300}
5301
5302template <>
5303EIGEN_STRONG_INLINE Packet2d ploaddup<Packet2d>(const double* from) {
5304 return vld1q_dup_f64(from);
5305}
5306template <>
5307EIGEN_STRONG_INLINE void pstore<double>(double* to, const Packet2d& from) {
5308 EIGEN_DEBUG_ALIGNED_STORE vst1q_f64(assume_aligned<unpacket_traits<Packet2d>::alignment>(to), from);
5309}
5310
5311template <>
5312EIGEN_STRONG_INLINE void pstoreu<double>(double* to, const Packet2d& from) {
5313 EIGEN_DEBUG_UNALIGNED_STORE vst1q_f64(to, from);
5314}
5315
5316template <>
5317EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet2d pgather<double, Packet2d>(const double* from, Index stride) {
5318 Packet2d res = pset1<Packet2d>(0.0);
5319 res = vld1q_lane_f64(from + 0 * stride, res, 0);
5320 res = vld1q_lane_f64(from + 1 * stride, res, 1);
5321 return res;
5322}
5323
5324template <>
5325EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter<double, Packet2d>(double* to, const Packet2d& from, Index stride) {
5326 vst1q_lane_f64(to + stride * 0, from, 0);
5327 vst1q_lane_f64(to + stride * 1, from, 1);
5328}
5329
5330template <>
5331EIGEN_STRONG_INLINE void prefetch<double>(const double* addr) {
5332 EIGEN_ARM_PREFETCH(addr);
5333}
5334
5335// FIXME only store the 2 first elements ?
5336template <>
5337EIGEN_STRONG_INLINE double pfirst<Packet2d>(const Packet2d& a) {
5338 return vgetq_lane_f64(a, 0);
5339}
5340
5341template <>
5342EIGEN_STRONG_INLINE Packet2d preverse(const Packet2d& a) {
5343 return vcombine_f64(vget_high_f64(a), vget_low_f64(a));
5344}
5345
5346template <>
5347EIGEN_STRONG_INLINE Packet2d pabs(const Packet2d& a) {
5348 return vabsq_f64(a);
5349}
5350
5351template <>
5352EIGEN_STRONG_INLINE Packet2d psignbit(const Packet2d& a) {
5353 return vreinterpretq_f64_s64(vshrq_n_s64(vreinterpretq_s64_f64(a), 63));
5354}
5355
5356template <>
5357EIGEN_STRONG_INLINE double predux<Packet2d>(const Packet2d& a) {
5358 return vaddvq_f64(a);
5359}
5360
5361template <>
5362EIGEN_STRONG_INLINE Index predux_count(const Packet2d& a) {
5363 // Each zero lane contributes UINT64_MAX, so unsigned 2 + sum(mask) is the number of nonzero lanes.
5364 const uint64_t zeroMaskSum = vaddvq_u64(vceqq_f64(a, vdupq_n_f64(0.0)));
5365 return static_cast<Index>(zeroMaskSum + 2);
5366}
5367
5368template <>
5369EIGEN_STRONG_INLINE bool predux_any(const Packet2d& a) {
5370 return vmaxvq_u32(vreinterpretq_u32_f64(a)) != 0;
5371}
5372
5373// Other reduction functions:
5374// mul
5375#if EIGEN_COMP_CLANGAPPLE
5376template <>
5377EIGEN_STRONG_INLINE double predux_mul<Packet2d>(const Packet2d& a) {
5378 return (vget_low_f64(a) * vget_high_f64(a))[0];
5379}
5380#else
5381template <>
5382EIGEN_STRONG_INLINE double predux_mul<Packet2d>(const Packet2d& a) {
5383 return vget_lane_f64(vmul_f64(vget_low_f64(a), vget_high_f64(a)), 0);
5384}
5385#endif
5386
5387// min
5388template <>
5389EIGEN_STRONG_INLINE double predux_min<Packet2d>(const Packet2d& a) {
5390 return vminvq_f64(a);
5391}
5392
5393// max
5394template <>
5395EIGEN_STRONG_INLINE double predux_max<Packet2d>(const Packet2d& a) {
5396 return vmaxvq_f64(a);
5397}
5398
5399EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet2d, 2>& kernel) {
5400 const float64x2_t tmp1 = vzip1q_f64(kernel.packet[0], kernel.packet[1]);
5401 const float64x2_t tmp2 = vzip2q_f64(kernel.packet[0], kernel.packet[1]);
5402
5403 kernel.packet[0] = tmp1;
5404 kernel.packet[1] = tmp2;
5405}
5406
5407template <>
5408EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet2d pselect(const Packet2d& mask, const Packet2d& a, const Packet2d& b) {
5409 return vbslq_f64(vreinterpretq_u64_f64(mask), a, b);
5410}
5411
5412template <>
5413EIGEN_STRONG_INLINE Packet2d print<Packet2d>(const Packet2d& a) {
5414 return vrndnq_f64(a);
5415}
5416
5417template <>
5418EIGEN_STRONG_INLINE Packet2d pfloor<Packet2d>(const Packet2d& a) {
5419 return vrndmq_f64(a);
5420}
5421
5422template <>
5423EIGEN_STRONG_INLINE Packet2d pceil<Packet2d>(const Packet2d& a) {
5424 return vrndpq_f64(a);
5425}
5426
5427template <>
5428EIGEN_STRONG_INLINE Packet2d pround<Packet2d>(const Packet2d& a) {
5429 return vrndaq_f64(a);
5430}
5431
5432template <>
5433EIGEN_STRONG_INLINE Packet2d ptrunc<Packet2d>(const Packet2d& a) {
5434 return vrndq_f64(a);
5435}
5436
5437template <>
5438EIGEN_STRONG_INLINE Packet2d pldexp<Packet2d>(const Packet2d& a, const Packet2d& exponent) {
5439 return pldexp_generic(a, exponent);
5440}
5441
5442template <>
5443EIGEN_STRONG_INLINE Packet2d pfrexp<Packet2d>(const Packet2d& a, Packet2d& exponent) {
5444 return pfrexp_generic(a, exponent);
5445}
5446
5447template <>
5448EIGEN_STRONG_INLINE Packet2d pset1frombits<Packet2d>(uint64_t from) {
5449 return vreinterpretq_f64_u64(vdupq_n_u64(from));
5450}
5451
5452template <>
5453EIGEN_STRONG_INLINE Packet2d prsqrt(const Packet2d& a) {
5454 // Do Newton iterations for 1/sqrt(x).
5455 return generic_rsqrt_newton_step<Packet2d, /*Steps=*/3>::run(a, vrsqrteq_f64(a));
5456}
5457
5458template <>
5459EIGEN_STRONG_INLINE Packet2d psqrt(const Packet2d& _x) {
5460 return vsqrtq_f64(_x);
5461}
5462
5463// Absolute comparisons as for Packet4f.
5464template <>
5465EIGEN_STRONG_INLINE Packet2d pisinf<Packet2d>(const Packet2d& a) {
5466 return vreinterpretq_f64_u64(vcageq_f64(a, pinf<Packet2d>()));
5467}
5468template <>
5469EIGEN_STRONG_INLINE Packet2d pisfinite<Packet2d>(const Packet2d& a) {
5470 return vreinterpretq_f64_u64(vcagtq_f64(pinf<Packet2d>(), a));
5471}
5472// |bits| > inf bits as an unsigned comparison. !vcage(inf, a) is one instruction shorter inside a select, but Clang's
5473// inliner charges more for the intrinsic, and pexp_complex<Packet1cd> sits within a few units of its threshold.
5474template <>
5475EIGEN_STRONG_INLINE Packet2d pisnan<Packet2d>(const Packet2d& a) {
5476 return vreinterpretq_f64_u64(vcgtq_u64(vreinterpretq_u64_f64(vabsq_f64(a)), vdupq_n_u64(0x7ff0000000000000ull)));
5477}
5478
5479#endif // EIGEN_ARCH_ARM64
5480
5481// Do we have fp16 and support Neon intrinsics?
5482// FIXME: This disables vectorization on ARMv7 even though FP16 vector operations should
5483// be available with `__ARM_FEATURE_FP16_VECTOR_ARITHMETIC`. However, since the internal
5484// feature test macro `EIGEN_HAS_ARM64_FP16_VECTOR_ARITHMETIC` requires `EIGEN_ARCH_ARM64`
5485// in addition to the ISA feature test, the guard here also only checks for ARM64.
5486#if EIGEN_ARCH_ARM64 && EIGEN_HAS_ARM64_FP16
5487typedef float16x4_t Packet4hf;
5488typedef float16x8_t Packet8hf;
5489
5490// Clang <19.1.0 does not provide `f16` intrinsics for pure data movement instructions.
5491// Polyfill them with `u16`.
5492//
5493// See: <https://github.com/llvm/llvm-project/pull/87467>.
5494#if EIGEN_CLANG_STRICT_LESS_THAN(19, 1, 0) && !EIGEN_HAS_ARM64_FP16_VECTOR_ARITHMETIC
5495EIGEN_ALWAYS_INLINE float16x4_t vbsl_f16(uint16x4_t a, float16x4_t b, float16x4_t c) {
5496 return vreinterpret_f16_u16(vbsl_u16(a, vreinterpret_u16_f16(b), vreinterpret_u16_f16(c)));
5497}
5498EIGEN_ALWAYS_INLINE float16x8_t vbslq_f16(uint16x8_t a, float16x8_t b, float16x8_t c) {
5499 return vreinterpretq_f16_u16(vbslq_u16(a, vreinterpretq_u16_f16(b), vreinterpretq_u16_f16(c)));
5500}
5501EIGEN_ALWAYS_INLINE float16x4_t vrev64_f16(float16x4_t a) {
5502 return vreinterpret_f16_u16(vrev64_u16(vreinterpret_u16_f16(a)));
5503}
5504EIGEN_ALWAYS_INLINE float16x8_t vrev64q_f16(float16x8_t a) {
5505 return vreinterpretq_f16_u16(vrev64q_u16(vreinterpretq_u16_f16(a)));
5506}
5507EIGEN_ALWAYS_INLINE float16x8x2_t vzipq_f16(float16x8_t a, float16x8_t b) {
5508 const uint16x8x2_t r = vzipq_u16(vreinterpretq_u16_f16(a), vreinterpretq_u16_f16(b));
5509 return {vreinterpretq_f16_u16(r.val[0]), vreinterpretq_f16_u16(r.val[1])};
5510}
5511EIGEN_ALWAYS_INLINE float16x8x2_t vuzpq_f16(float16x8_t a, float16x8_t b) {
5512 const uint16x8x2_t r = vuzpq_u16(vreinterpretq_u16_f16(a), vreinterpretq_u16_f16(b));
5513 return {vreinterpretq_f16_u16(r.val[0]), vreinterpretq_f16_u16(r.val[1])};
5514}
5515#endif // EIGEN_CLANG_STRICT_LESS_THAN(19, 1, 0) && !EIGEN_HAS_ARM64_FP16_VECTOR_ARITHMETIC
5516
5517template <>
5518struct packet_traits<half> : default_packet_traits {
5519 typedef Packet8hf type;
5520 typedef Packet4hf half;
5521 enum {
5522 Vectorizable = 1,
5523 AlignedOnScalar = 1,
5524 size = 8,
5525
5526 HasCmp = 1,
5527 HasCast = 1,
5528 HasAdd = 1,
5529 HasSub = 1,
5530 HasShift = 1,
5531 HasMul = 1,
5532 HasNegate = 1,
5533 HasAbs = 1,
5534 HasArg = 0,
5535 HasAbsDiff = 0,
5536 HasMin = 1,
5537 HasMax = 1,
5538 HasConj = 1,
5539 HasSetLinear = 1,
5540 HasInsert = 1,
5541 HasReduxp = 1,
5542 HasDiv = 1,
5543 HasSin = 0,
5544 HasCos = 0,
5545 HasLog = 0,
5546 HasExp = 0,
5547 HasTanh = packet_traits<float>::HasTanh, // tanh<half> calls tanh<float>
5548 HasSqrt = 1,
5549 HasRsqrt = 1,
5550 HasErf = EIGEN_FAST_MATH,
5551 HasBessel = 0, // Issues with accuracy.
5552 HasNdtri = 0
5553 };
5554};
5555
5556template <>
5557struct unpacket_traits<Packet4hf> : neon_unpacket_default<Packet4hf, half> {};
5558template <>
5559struct unpacket_traits<Packet8hf> : neon_unpacket_default<Packet8hf, half> {
5560 using half = Packet4hf;
5561};
5562
5563template <>
5564struct pminmax_propagates_nan<Packet4hf> : bool_constant<true> {};
5565template <>
5566struct pminmax_propagates_nan<Packet8hf> : bool_constant<true> {};
5567
5568template <>
5569EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf pset1(const half& from) {
5570 return vdupq_n_f16(from.x);
5571}
5572template <>
5573EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf pset1(const half& from) {
5574 return vdup_n_f16(from.x);
5575}
5576
5577#define EIGEN_MAKE_HALF_BITWISE_BINOP(name, op) \
5578 template <> \
5579 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf name(const Packet8hf& a, const Packet8hf& b) { \
5580 return vreinterpretq_f16_u16(v##op##q_u16(vreinterpretq_u16_f16(a), vreinterpretq_u16_f16(b))); \
5581 } \
5582 template <> \
5583 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf name(const Packet4hf& a, const Packet4hf& b) { \
5584 return vreinterpret_f16_u16(v##op##_u16(vreinterpret_u16_f16(a), vreinterpret_u16_f16(b))); \
5585 } \
5586 static_assert(true, "Trailing semicolon required")
5587
5588EIGEN_MAKE_HALF_BITWISE_BINOP(pand, and);
5589EIGEN_MAKE_HALF_BITWISE_BINOP(por, orr);
5590EIGEN_MAKE_HALF_BITWISE_BINOP(pxor, eor);
5591EIGEN_MAKE_HALF_BITWISE_BINOP(pandnot, bic);
5592
5593#undef EIGEN_MAKE_HALF_BITWISE_BINOP
5594
5595template <>
5596EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf pload(const half* from) {
5597 EIGEN_DEBUG_ALIGNED_LOAD return vld1q_f16(assume_aligned<unpacket_traits<Packet8hf>::alignment>(&from->x));
5598}
5599template <>
5600EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf pload(const half* from) {
5601 EIGEN_DEBUG_ALIGNED_LOAD return vld1_f16(assume_aligned<unpacket_traits<Packet4hf>::alignment>(&from->x));
5602}
5603
5604template <>
5605EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf ploadu(const half* from) {
5606 EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_f16(&from->x);
5607}
5608template <>
5609EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf ploadu(const half* from) {
5610 EIGEN_DEBUG_UNALIGNED_LOAD return vld1_f16(&from->x);
5611}
5612
5613template <>
5614EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf ploaddup(const half* from) {
5615 Packet8hf packet{};
5616 packet = vsetq_lane_f16(from[0].x, packet, 0);
5617 packet = vsetq_lane_f16(from[0].x, packet, 1);
5618 packet = vsetq_lane_f16(from[1].x, packet, 2);
5619 packet = vsetq_lane_f16(from[1].x, packet, 3);
5620 packet = vsetq_lane_f16(from[2].x, packet, 4);
5621 packet = vsetq_lane_f16(from[2].x, packet, 5);
5622 packet = vsetq_lane_f16(from[3].x, packet, 6);
5623 packet = vsetq_lane_f16(from[3].x, packet, 7);
5624 return packet;
5625}
5626template <>
5627EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf ploaddup(const half* from) {
5628 float16x4_t packet{};
5629 packet = vset_lane_f16(from[0].x, packet, 0);
5630 packet = vset_lane_f16(from[0].x, packet, 1);
5631 packet = vset_lane_f16(from[1].x, packet, 2);
5632 packet = vset_lane_f16(from[1].x, packet, 3);
5633 return packet;
5634}
5635
5636template <>
5637EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf ploadquad(const half* from) {
5638 Packet4hf lo, hi;
5639 lo = vld1_dup_f16(&from[0].x);
5640 hi = vld1_dup_f16(&from[1].x);
5641 return vcombine_f16(lo, hi);
5642}
5643
5644EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf pinsertfirst(const Packet8hf& a, half b) {
5645 return vsetq_lane_f16(b.x, a, 0);
5646}
5647EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf pinsertfirst(const Packet4hf& a, half b) {
5648 return vset_lane_f16(b.x, a, 0);
5649}
5650
5651template <>
5652EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf pselect(const Packet8hf& mask, const Packet8hf& a, const Packet8hf& b) {
5653 return vbslq_f16(vreinterpretq_u16_f16(mask), a, b);
5654}
5655template <>
5656EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf pselect(const Packet4hf& mask, const Packet4hf& a, const Packet4hf& b) {
5657 return vbsl_f16(vreinterpret_u16_f16(mask), a, b);
5658}
5659
5660EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf pinsertlast(const Packet8hf& a, half b) {
5661 return vsetq_lane_f16(b.x, a, 7);
5662}
5663EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf pinsertlast(const Packet4hf& a, half b) {
5664 return vset_lane_f16(b.x, a, 3);
5665}
5666
5667template <>
5668EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pstore(half* to, const Packet8hf& from) {
5669 EIGEN_DEBUG_ALIGNED_STORE vst1q_f16(assume_aligned<unpacket_traits<Packet8hf>::alignment>(&to->x), from);
5670}
5671template <>
5672EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pstore(half* to, const Packet4hf& from) {
5673 EIGEN_DEBUG_ALIGNED_STORE vst1_f16(assume_aligned<unpacket_traits<Packet4hf>::alignment>(&to->x), from);
5674}
5675
5676template <>
5677EIGEN_STRONG_INLINE void pstoreu(half* to, const Packet8hf& from) {
5678 EIGEN_DEBUG_UNALIGNED_STORE vst1q_f16(&to->x, from);
5679}
5680template <>
5681EIGEN_STRONG_INLINE void pstoreu(half* to, const Packet4hf& from) {
5682 EIGEN_DEBUG_UNALIGNED_STORE vst1_f16(&to->x, from);
5683}
5684
5685template <>
5686EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf pgather(const half* from, Index stride) {
5687 Packet8hf res = pset1<Packet8hf>(half(0.f));
5688 res = vsetq_lane_f16(from[0 * stride].x, res, 0);
5689 res = vsetq_lane_f16(from[1 * stride].x, res, 1);
5690 res = vsetq_lane_f16(from[2 * stride].x, res, 2);
5691 res = vsetq_lane_f16(from[3 * stride].x, res, 3);
5692 res = vsetq_lane_f16(from[4 * stride].x, res, 4);
5693 res = vsetq_lane_f16(from[5 * stride].x, res, 5);
5694 res = vsetq_lane_f16(from[6 * stride].x, res, 6);
5695 res = vsetq_lane_f16(from[7 * stride].x, res, 7);
5696 return res;
5697}
5698template <>
5699EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf pgather(const half* from, Index stride) {
5700 Packet4hf res = pset1<Packet4hf>(half(0.f));
5701 res = vset_lane_f16(from[0 * stride].x, res, 0);
5702 res = vset_lane_f16(from[1 * stride].x, res, 1);
5703 res = vset_lane_f16(from[2 * stride].x, res, 2);
5704 res = vset_lane_f16(from[3 * stride].x, res, 3);
5705 return res;
5706}
5707
5708template <>
5709EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter(half* to, const Packet8hf& from, Index stride) {
5710 to[stride * 0].x = vgetq_lane_f16(from, 0);
5711 to[stride * 1].x = vgetq_lane_f16(from, 1);
5712 to[stride * 2].x = vgetq_lane_f16(from, 2);
5713 to[stride * 3].x = vgetq_lane_f16(from, 3);
5714 to[stride * 4].x = vgetq_lane_f16(from, 4);
5715 to[stride * 5].x = vgetq_lane_f16(from, 5);
5716 to[stride * 6].x = vgetq_lane_f16(from, 6);
5717 to[stride * 7].x = vgetq_lane_f16(from, 7);
5718}
5719template <>
5720EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pscatter(half* to, const Packet4hf& from, Index stride) {
5721 to[stride * 0].x = vget_lane_f16(from, 0);
5722 to[stride * 1].x = vget_lane_f16(from, 1);
5723 to[stride * 2].x = vget_lane_f16(from, 2);
5724 to[stride * 3].x = vget_lane_f16(from, 3);
5725}
5726
5727template <>
5728EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void prefetch(const half* addr) {
5729 EIGEN_ARM_PREFETCH(addr);
5730}
5731
5732template <>
5733EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half pfirst(const Packet8hf& a) {
5734 return half(vgetq_lane_f16(a, 0));
5735}
5736template <>
5737EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half pfirst(const Packet4hf& a) {
5738 return half(vget_lane_f16(a, 0));
5739}
5740
5741template <>
5742EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf preverse(const Packet8hf& a) {
5743 float16x8_t r = vrev64q_f16(a);
5744 return vcombine_f16(vget_high_f16(r), vget_low_f16(r));
5745}
5746template <>
5747EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf preverse(const Packet4hf& a) {
5748 return vrev64_f16(a);
5749}
5750
5751template <>
5752EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf psignbit(const Packet8hf& a) {
5753 return vreinterpretq_f16_s16(vshrq_n_s16(vreinterpretq_s16_f16(a), 15));
5754}
5755template <>
5756EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf psignbit(const Packet4hf& a) {
5757 return vreinterpret_f16_s16(vshr_n_s16(vreinterpret_s16_f16(a), 15));
5758}
5759
5760template <>
5761EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool predux_any(const Packet8hf& a) {
5762 return vget_lane_u64(vreinterpret_u64_u8(vmovn_u16(vreinterpretq_u16_f16(a))), 0);
5763}
5764template <>
5765EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool predux_any(const Packet4hf& a) {
5766 return vget_lane_u64(vreinterpret_u64_f16(a), 0);
5767}
5768
5769EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet8hf, 4>& kernel) {
5770 const float16x8x2_t zip16_1 = vzipq_f16(kernel.packet[0], kernel.packet[1]);
5771 const float16x8x2_t zip16_2 = vzipq_f16(kernel.packet[2], kernel.packet[3]);
5772
5773 const float32x4x2_t zip32_1 = vzipq_f32(vreinterpretq_f32_f16(zip16_1.val[0]), vreinterpretq_f32_f16(zip16_2.val[0]));
5774 const float32x4x2_t zip32_2 = vzipq_f32(vreinterpretq_f32_f16(zip16_1.val[1]), vreinterpretq_f32_f16(zip16_2.val[1]));
5775
5776 kernel.packet[0] = vreinterpretq_f16_f32(zip32_1.val[0]);
5777 kernel.packet[1] = vreinterpretq_f16_f32(zip32_1.val[1]);
5778 kernel.packet[2] = vreinterpretq_f16_f32(zip32_2.val[0]);
5779 kernel.packet[3] = vreinterpretq_f16_f32(zip32_2.val[1]);
5780}
5781EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet4hf, 4>& kernel) {
5782 EIGEN_ALIGN16 float16x4x4_t tmp_x4;
5783 float16_t* tmp = reinterpret_cast<float16_t*>(&kernel);
5784 tmp_x4 = vld4_f16(tmp);
5785
5786 kernel.packet[0] = tmp_x4.val[0];
5787 kernel.packet[1] = tmp_x4.val[1];
5788 kernel.packet[2] = tmp_x4.val[2];
5789 kernel.packet[3] = tmp_x4.val[3];
5790}
5791
5792EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet8hf, 8>& kernel) {
5793 float16x8x2_t T_1[4];
5794
5795 T_1[0] = vuzpq_f16(kernel.packet[0], kernel.packet[1]);
5796 T_1[1] = vuzpq_f16(kernel.packet[2], kernel.packet[3]);
5797 T_1[2] = vuzpq_f16(kernel.packet[4], kernel.packet[5]);
5798 T_1[3] = vuzpq_f16(kernel.packet[6], kernel.packet[7]);
5799
5800 float16x8x2_t T_2[4];
5801 T_2[0] = vuzpq_f16(T_1[0].val[0], T_1[1].val[0]);
5802 T_2[1] = vuzpq_f16(T_1[0].val[1], T_1[1].val[1]);
5803 T_2[2] = vuzpq_f16(T_1[2].val[0], T_1[3].val[0]);
5804 T_2[3] = vuzpq_f16(T_1[2].val[1], T_1[3].val[1]);
5805
5806 float16x8x2_t T_3[4];
5807 T_3[0] = vuzpq_f16(T_2[0].val[0], T_2[2].val[0]);
5808 T_3[1] = vuzpq_f16(T_2[0].val[1], T_2[2].val[1]);
5809 T_3[2] = vuzpq_f16(T_2[1].val[0], T_2[3].val[0]);
5810 T_3[3] = vuzpq_f16(T_2[1].val[1], T_2[3].val[1]);
5811
5812 kernel.packet[0] = T_3[0].val[0];
5813 kernel.packet[1] = T_3[2].val[0];
5814 kernel.packet[2] = T_3[1].val[0];
5815 kernel.packet[3] = T_3[3].val[0];
5816 kernel.packet[4] = T_3[0].val[1];
5817 kernel.packet[5] = T_3[2].val[1];
5818 kernel.packet[6] = T_3[1].val[1];
5819 kernel.packet[7] = T_3[3].val[1];
5820}
5821
5822#if EIGEN_HAS_ARM64_FP16_VECTOR_ARITHMETIC
5823
5824template <>
5825EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf predux_half<Packet8hf>(const Packet8hf& a) {
5826 return vadd_f16(vget_low_f16(a), vget_high_f16(a));
5827}
5828
5829template <>
5830EIGEN_STRONG_INLINE Packet8hf plset<Packet8hf>(const Eigen::half& a) {
5831 const float16_t f[] = {0, 1, 2, 3, 4, 5, 6, 7};
5832 Packet8hf countdown = vld1q_f16(f);
5833 return vaddq_f16(pset1<Packet8hf>(a), countdown);
5834}
5835
5836template <>
5837EIGEN_STRONG_INLINE Packet4hf plset<Packet4hf>(const Eigen::half& a) {
5838 const float16_t f[] = {0, 1, 2, 3};
5839 Packet4hf countdown = vld1_f16(f);
5840 return vadd_f16(pset1<Packet4hf>(a), countdown);
5841}
5842
5843template <>
5844EIGEN_STRONG_INLINE Packet8hf padd<Packet8hf>(const Packet8hf& a, const Packet8hf& b) {
5845 return vaddq_f16(a, b);
5846}
5847
5848template <>
5849EIGEN_STRONG_INLINE Packet4hf padd<Packet4hf>(const Packet4hf& a, const Packet4hf& b) {
5850 return vadd_f16(a, b);
5851}
5852
5853template <>
5854EIGEN_STRONG_INLINE Packet8hf psub<Packet8hf>(const Packet8hf& a, const Packet8hf& b) {
5855 return vsubq_f16(a, b);
5856}
5857
5858template <>
5859EIGEN_STRONG_INLINE Packet4hf psub<Packet4hf>(const Packet4hf& a, const Packet4hf& b) {
5860 return vsub_f16(a, b);
5861}
5862
5863template <>
5864EIGEN_STRONG_INLINE Packet8hf pnegate(const Packet8hf& a) {
5865 return vnegq_f16(a);
5866}
5867
5868template <>
5869EIGEN_STRONG_INLINE Packet4hf pnegate(const Packet4hf& a) {
5870 return vneg_f16(a);
5871}
5872
5873template <>
5874EIGEN_STRONG_INLINE Packet8hf pmul<Packet8hf>(const Packet8hf& a, const Packet8hf& b) {
5875 return vmulq_f16(a, b);
5876}
5877
5878template <>
5879EIGEN_STRONG_INLINE Packet4hf pmul<Packet4hf>(const Packet4hf& a, const Packet4hf& b) {
5880 return vmul_f16(a, b);
5881}
5882
5883template <>
5884EIGEN_STRONG_INLINE Packet8hf pdiv<Packet8hf>(const Packet8hf& a, const Packet8hf& b) {
5885 return vdivq_f16(a, b);
5886}
5887
5888template <>
5889EIGEN_STRONG_INLINE Packet4hf pdiv<Packet4hf>(const Packet4hf& a, const Packet4hf& b) {
5890 return vdiv_f16(a, b);
5891}
5892
5893template <>
5894EIGEN_STRONG_INLINE Packet8hf pmadd(const Packet8hf& a, const Packet8hf& b, const Packet8hf& c) {
5895 return vfmaq_f16(c, a, b);
5896}
5897
5898template <>
5899EIGEN_STRONG_INLINE Packet4hf pmadd(const Packet4hf& a, const Packet4hf& b, const Packet4hf& c) {
5900 return vfma_f16(c, a, b);
5901}
5902
5903template <>
5904EIGEN_STRONG_INLINE Packet8hf pnmadd(const Packet8hf& a, const Packet8hf& b, const Packet8hf& c) {
5905 return vfmsq_f16(c, a, b);
5906}
5907
5908template <>
5909EIGEN_STRONG_INLINE Packet4hf pnmadd(const Packet4hf& a, const Packet4hf& b, const Packet4hf& c) {
5910 return vfms_f16(c, a, b);
5911}
5912
5913template <>
5914EIGEN_STRONG_INLINE Packet8hf pmin<Packet8hf>(const Packet8hf& a, const Packet8hf& b) {
5915 return vminq_f16(a, b);
5916}
5917
5918template <>
5919EIGEN_STRONG_INLINE Packet4hf pmin<Packet4hf>(const Packet4hf& a, const Packet4hf& b) {
5920 return vmin_f16(a, b);
5921}
5922
5923#ifdef __ARM_FEATURE_NUMERIC_MAXMIN
5924// numeric max and min are only available if ARM_FEATURE_NUMERIC_MAXMIN is defined (which can only be the case for Armv8
5925// systems).
5926template <>
5927EIGEN_STRONG_INLINE Packet4hf pmin<PropagateNumbers, Packet4hf>(const Packet4hf& a, const Packet4hf& b) {
5928 return vminnm_f16(a, b);
5929}
5930template <>
5931EIGEN_STRONG_INLINE Packet8hf pmin<PropagateNumbers, Packet8hf>(const Packet8hf& a, const Packet8hf& b) {
5932 return vminnmq_f16(a, b);
5933}
5934#endif
5935
5936template <>
5937EIGEN_STRONG_INLINE Packet8hf pmax<Packet8hf>(const Packet8hf& a, const Packet8hf& b) {
5938 return vmaxq_f16(a, b);
5939}
5940
5941template <>
5942EIGEN_STRONG_INLINE Packet4hf pmax<Packet4hf>(const Packet4hf& a, const Packet4hf& b) {
5943 return vmax_f16(a, b);
5944}
5945
5946#ifdef __ARM_FEATURE_NUMERIC_MAXMIN
5947// numeric max and min are only available if ARM_FEATURE_NUMERIC_MAXMIN is defined (which can only be the case for Armv8
5948// systems).
5949template <>
5950EIGEN_STRONG_INLINE Packet4hf pmax<PropagateNumbers, Packet4hf>(const Packet4hf& a, const Packet4hf& b) {
5951 return vmaxnm_f16(a, b);
5952}
5953template <>
5954EIGEN_STRONG_INLINE Packet8hf pmax<PropagateNumbers, Packet8hf>(const Packet8hf& a, const Packet8hf& b) {
5955 return vmaxnmq_f16(a, b);
5956}
5957#endif
5958
5959#define EIGEN_MAKE_ARM_FP16_CMP_8(name) \
5960 template <> \
5961 EIGEN_STRONG_INLINE Packet8hf pcmp_##name(const Packet8hf& a, const Packet8hf& b) { \
5962 return vreinterpretq_f16_u16(vc##name##q_f16(a, b)); \
5963 }
5964
5965#define EIGEN_MAKE_ARM_FP16_CMP_4(name) \
5966 template <> \
5967 EIGEN_STRONG_INLINE Packet4hf pcmp_##name(const Packet4hf& a, const Packet4hf& b) { \
5968 return vreinterpret_f16_u16(vc##name##_f16(a, b)); \
5969 }
5970
5971EIGEN_MAKE_ARM_FP16_CMP_8(eq)
5972EIGEN_MAKE_ARM_FP16_CMP_8(lt)
5973EIGEN_MAKE_ARM_FP16_CMP_8(le)
5974
5975EIGEN_MAKE_ARM_FP16_CMP_4(eq)
5976EIGEN_MAKE_ARM_FP16_CMP_4(lt)
5977EIGEN_MAKE_ARM_FP16_CMP_4(le)
5978
5979#undef EIGEN_MAKE_ARM_FP16_CMP_8
5980#undef EIGEN_MAKE_ARM_FP16_CMP_4
5981
5982template <>
5983EIGEN_STRONG_INLINE Packet8hf pcmp_lt_or_nan<Packet8hf>(const Packet8hf& a, const Packet8hf& b) {
5984 return vreinterpretq_f16_u16(vmvnq_u16(vcgeq_f16(a, b)));
5985}
5986
5987template <>
5988EIGEN_STRONG_INLINE Packet4hf pcmp_lt_or_nan<Packet4hf>(const Packet4hf& a, const Packet4hf& b) {
5989 return vreinterpret_f16_u16(vmvn_u16(vcge_f16(a, b)));
5990}
5991
5992// Absolute comparisons as for Packet4f.
5993template <>
5994EIGEN_STRONG_INLINE Packet4hf pisinf<Packet4hf>(const Packet4hf& a) {
5995 return vreinterpret_f16_u16(vcage_f16(a, pinf<Packet4hf>()));
5996}
5997template <>
5998EIGEN_STRONG_INLINE Packet8hf pisinf<Packet8hf>(const Packet8hf& a) {
5999 return vreinterpretq_f16_u16(vcageq_f16(a, pinf<Packet8hf>()));
6000}
6001template <>
6002EIGEN_STRONG_INLINE Packet4hf pisfinite<Packet4hf>(const Packet4hf& a) {
6003 return vreinterpret_f16_u16(vcagt_f16(pinf<Packet4hf>(), a));
6004}
6005template <>
6006EIGEN_STRONG_INLINE Packet8hf pisfinite<Packet8hf>(const Packet8hf& a) {
6007 return vreinterpretq_f16_u16(vcagtq_f16(pinf<Packet8hf>(), a));
6008}
6009template <>
6010EIGEN_STRONG_INLINE Packet4hf pisnan<Packet4hf>(const Packet4hf& a) {
6011 return vreinterpret_f16_u16(vmvn_u16(vcage_f16(pinf<Packet4hf>(), a)));
6012}
6013template <>
6014EIGEN_STRONG_INLINE Packet8hf pisnan<Packet8hf>(const Packet8hf& a) {
6015 return vreinterpretq_f16_u16(vmvnq_u16(vcageq_f16(pinf<Packet8hf>(), a)));
6016}
6017
6018template <>
6019EIGEN_STRONG_INLINE Packet8hf print<Packet8hf>(const Packet8hf& a) {
6020 return vrndnq_f16(a);
6021}
6022
6023template <>
6024EIGEN_STRONG_INLINE Packet4hf print<Packet4hf>(const Packet4hf& a) {
6025 return vrndn_f16(a);
6026}
6027
6028template <>
6029EIGEN_STRONG_INLINE Packet8hf pfloor<Packet8hf>(const Packet8hf& a) {
6030 return vrndmq_f16(a);
6031}
6032
6033template <>
6034EIGEN_STRONG_INLINE Packet4hf pfloor<Packet4hf>(const Packet4hf& a) {
6035 return vrndm_f16(a);
6036}
6037
6038template <>
6039EIGEN_STRONG_INLINE Packet8hf pceil<Packet8hf>(const Packet8hf& a) {
6040 return vrndpq_f16(a);
6041}
6042
6043template <>
6044EIGEN_STRONG_INLINE Packet4hf pceil<Packet4hf>(const Packet4hf& a) {
6045 return vrndp_f16(a);
6046}
6047
6048template <>
6049EIGEN_STRONG_INLINE Packet8hf pround<Packet8hf>(const Packet8hf& a) {
6050 return vrndaq_f16(a);
6051}
6052
6053template <>
6054EIGEN_STRONG_INLINE Packet4hf pround<Packet4hf>(const Packet4hf& a) {
6055 return vrnda_f16(a);
6056}
6057
6058template <>
6059EIGEN_STRONG_INLINE Packet8hf ptrunc<Packet8hf>(const Packet8hf& a) {
6060 return vrndq_f16(a);
6061}
6062
6063template <>
6064EIGEN_STRONG_INLINE Packet4hf ptrunc<Packet4hf>(const Packet4hf& a) {
6065 return vrnd_f16(a);
6066}
6067
6068template <>
6069EIGEN_STRONG_INLINE Packet8hf psqrt<Packet8hf>(const Packet8hf& a) {
6070 return vsqrtq_f16(a);
6071}
6072
6073template <>
6074EIGEN_STRONG_INLINE Packet4hf psqrt<Packet4hf>(const Packet4hf& a) {
6075 return vsqrt_f16(a);
6076}
6077
6078template <>
6079EIGEN_STRONG_INLINE Packet8hf pabs<Packet8hf>(const Packet8hf& a) {
6080 return vabsq_f16(a);
6081}
6082
6083template <>
6084EIGEN_STRONG_INLINE Packet4hf pabs<Packet4hf>(const Packet4hf& a) {
6085 return vabs_f16(a);
6086}
6087
6088template <>
6089EIGEN_STRONG_INLINE Eigen::half predux<Packet8hf>(const Packet8hf& a) {
6090 float16x4_t a_lo, a_hi, sum;
6091
6092 a_lo = vget_low_f16(a);
6093 a_hi = vget_high_f16(a);
6094 sum = vpadd_f16(a_lo, a_hi);
6095 sum = vpadd_f16(sum, sum);
6096 sum = vpadd_f16(sum, sum);
6097
6098 Eigen::half h;
6099 h.x = vget_lane_f16(sum, 0);
6100 return h;
6101}
6102
6103template <>
6104EIGEN_STRONG_INLINE Eigen::half predux<Packet4hf>(const Packet4hf& a) {
6105 float16x4_t sum;
6106
6107 sum = vpadd_f16(a, a);
6108 sum = vpadd_f16(sum, sum);
6109 Eigen::half h;
6110 h.x = vget_lane_f16(sum, 0);
6111 return h;
6112}
6113
6114template <>
6115EIGEN_STRONG_INLINE Eigen::half predux_mul<Packet8hf>(const Packet8hf& a) {
6116 float16x4_t a_lo, a_hi, prod;
6117
6118 a_lo = vget_low_f16(a);
6119 a_hi = vget_high_f16(a);
6120 prod = vmul_f16(a_lo, a_hi);
6121 prod = vmul_f16(prod, vrev64_f16(prod));
6122
6123 Eigen::half h;
6124 h.x = vmulh_f16(vget_lane_f16(prod, 0), vget_lane_f16(prod, 1));
6125 return h;
6126}
6127
6128template <>
6129EIGEN_STRONG_INLINE Eigen::half predux_mul<Packet4hf>(const Packet4hf& a) {
6130 float16x4_t prod;
6131 prod = vmul_f16(a, vrev64_f16(a));
6132 Eigen::half h;
6133 h.x = vmulh_f16(vget_lane_f16(prod, 0), vget_lane_f16(prod, 1));
6134 return h;
6135}
6136
6137template <>
6138EIGEN_STRONG_INLINE Eigen::half predux_min<Packet8hf>(const Packet8hf& a) {
6139 Eigen::half h;
6140 h.x = vminvq_f16(a);
6141 return h;
6142}
6143
6144template <>
6145EIGEN_STRONG_INLINE Eigen::half predux_min<Packet4hf>(const Packet4hf& a) {
6146 Eigen::half h;
6147 h.x = vminv_f16(a);
6148 return h;
6149}
6150
6151template <>
6152EIGEN_STRONG_INLINE Eigen::half predux_max<Packet8hf>(const Packet8hf& a) {
6153 Eigen::half h;
6154 h.x = vmaxvq_f16(a);
6155 return h;
6156}
6157
6158template <>
6159EIGEN_STRONG_INLINE Eigen::half predux_max<Packet4hf>(const Packet4hf& a) {
6160 Eigen::half h;
6161 h.x = vmaxv_f16(a);
6162 return h;
6163}
6164
6165#else
6166
6167// Even if we do not have native vector arithmetic on fp16 types, we can still
6168// assume the presence of conversion instructions to/from fp32 on AArch64
6169// ([ref]). As a result, packet arithmetic on AArch64 without `+fp16` is
6170// implemented through conversion to fp32. Beware that this comes at the
6171// expense of additional instructions for casting and potential differences in
6172// floating-point error accumulation. The performance is still much better than
6173// manual fp16, however.
6174//
6175// [ref]:
6176// <https://developer.arm.com/documentation/101028/0012/13--Advanced-SIMD--Neon--intrinsics#availability-of-16-bit-floating-point-vector-interchange-types>
6177
6178template <>
6179EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf predux_half(const Packet8hf& a) {
6180 return vcvt_f16_f32(vaddq_f32(vcvt_f32_f16(vget_low_f16(a)), vcvt_f32_f16(vget_high_f16(a))));
6181}
6182
6183template <>
6184EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf plset(const half& a) {
6185 const float f[] = {0, 1, 2, 3};
6186 float32x4_t countdown = vld1q_f32(f);
6187 float32x4_t base = vaddq_f32(vcvt_f32_f16(pset1<Packet4hf>(a)), countdown);
6188 return vcombine_f16(vcvt_f16_f32(base), vcvt_f16_f32(vaddq_f32(base, vdupq_n_f32(4))));
6189}
6190template <>
6191EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf plset(const half& a) {
6192 const float f[] = {0, 1, 2, 3};
6193 Packet4f countdown = vld1q_f32(f);
6194 return vcvt_f16_f32(vaddq_f32(pset1<Packet4f>(a), countdown));
6195}
6196
6197#define EIGEN_MAKE_HALF_UNOP(name, op) \
6198 template <> \
6199 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf name(const Packet4hf& a) { \
6200 return vcvt_f16_f32(v##op##q_f32(vcvt_f32_f16(a))); \
6201 } \
6202 template <> \
6203 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf name(const Packet8hf& a) { \
6204 return vcombine_f16(name(vget_low_f16(a)), name(vget_high_f16(a))); \
6205 } \
6206 static_assert(true, "Trailing semicolon required")
6207#define EIGEN_MAKE_HALF_BINOP(name, op) \
6208 template <> \
6209 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf name(const Packet4hf& a, const Packet4hf& b) { \
6210 return vcvt_f16_f32(v##op##q_f32(vcvt_f32_f16(a), vcvt_f32_f16(b))); \
6211 } \
6212 template <> \
6213 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf name(const Packet8hf& a, const Packet8hf& b) { \
6214 return vcombine_f16(name(vget_low_f16(a), vget_low_f16(b)), name(vget_high_f16(a), vget_high_f16(b))); \
6215 } \
6216 static_assert(true, "Trailing semicolon required")
6217
6218EIGEN_MAKE_HALF_BINOP(padd, add);
6219EIGEN_MAKE_HALF_BINOP(psub, sub);
6220
6221template <>
6222EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf pnegate(const Packet8hf& a) {
6223 return vreinterpretq_f16_u16(veorq_u16(vreinterpretq_u16_f16(a), vdupq_n_u16(0x8000)));
6224}
6225template <>
6226EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf pnegate(const Packet4hf& a) {
6227 return vreinterpret_f16_u16(veor_u16(vreinterpret_u16_f16(a), vdup_n_u16(0x8000)));
6228}
6229
6230EIGEN_MAKE_HALF_BINOP(pmul, mul);
6231
6232#if EIGEN_ARCH_ARM64
6233EIGEN_MAKE_HALF_BINOP(pdiv, div);
6234#else
6235template <>
6236EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf pdiv(const Packet4hf& a, const Packet4hf& b) {
6237 return vcvt_f16_f32(pdiv(vcvt_f32_f16(a), vcvt_f32_f16(b)));
6238}
6239template <>
6240EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf pdiv(const Packet8hf& a, const Packet8hf& b) {
6241 return vcombine_f16(pdiv(vget_low_f16(a), vget_low_f16(b)), pdiv(vget_high_f16(a), vget_high_f16(b)));
6242}
6243#endif
6244
6245#define EIGEN_MAKE_HALF_FMA(name, op) \
6246 template <> \
6247 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf name(const Packet4hf& a, const Packet4hf& b, const Packet4hf& c) { \
6248 return vcvt_f16_f32(v##op##q_f32(vcvt_f32_f16(c), vcvt_f32_f16(a), vcvt_f32_f16(b))); \
6249 } \
6250 template <> \
6251 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf name(const Packet8hf& a, const Packet8hf& b, const Packet8hf& c) { \
6252 return vcombine_f16(name(vget_low_f16(a), vget_low_f16(b), vget_low_f16(c)), \
6253 name(vget_high_f16(a), vget_high_f16(b), vget_high_f16(c))); \
6254 } \
6255 static_assert(true, "Trailing semicolon required")
6256
6257EIGEN_MAKE_HALF_FMA(pmadd, fma);
6258EIGEN_MAKE_HALF_FMA(pnmadd, fms);
6259
6260#undef EIGEN_MAKE_HALF_FMA
6261
6262EIGEN_MAKE_HALF_BINOP(pmin, min);
6263EIGEN_MAKE_HALF_BINOP(pmax, max);
6264
6265#ifdef __ARM_FEATURE_NUMERIC_MAXMIN
6266
6267#define EIGEN_MAKE_HALF_NUMERIC_MAXMIN(name) \
6268 template <> \
6269 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf p##name<PropagateNumbers, Packet4hf>(const Packet4hf& a, \
6270 const Packet4hf& b) { \
6271 return vcvt_f16_f32(v##name##nmq_f32(vcvt_f32_f16(a), vcvt_f32_f16(b))); \
6272 } \
6273 template <> \
6274 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf p##name<PropagateNumbers, Packet8hf>(const Packet8hf& a, \
6275 const Packet8hf& b) { \
6276 return vcombine_f16(p##name<PropagateNumbers, Packet4hf>(vget_low_f16(a), vget_low_f16(b)), \
6277 p##name<PropagateNumbers, Packet4hf>(vget_high_f16(a), vget_high_f16(b))); \
6278 } \
6279 static_assert(true, "Trailing semicolon required")
6280
6281EIGEN_MAKE_HALF_NUMERIC_MAXMIN(min);
6282EIGEN_MAKE_HALF_NUMERIC_MAXMIN(max);
6283
6284#undef EIGEN_MAKE_HALF_NUMERIC_MAXMIN
6285
6286#endif
6287
6288#define EIGEN_MAKE_HALF_CMP(name) \
6289 template <> \
6290 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf pcmp_##name(const Packet4hf& a, const Packet4hf& b) { \
6291 return vreinterpret_f16_u16(vmovn_u32(vc##name##q_f32(vcvt_f32_f16(a), vcvt_f32_f16(b)))); \
6292 } \
6293 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf pcmp_##name(const Packet8hf& a, const Packet8hf& b) { \
6294 return vcombine_f16(pcmp_##name(vget_low_f16(a), vget_low_f16(b)), \
6295 pcmp_##name(vget_high_f16(a), vget_high_f16(b))); \
6296 } \
6297 static_assert(true, "Trailing semicolon required")
6298
6299EIGEN_MAKE_HALF_CMP(eq);
6300EIGEN_MAKE_HALF_CMP(lt);
6301EIGEN_MAKE_HALF_CMP(le);
6302
6303#undef EIGEN_MAKE_HALF_CMP
6304
6305template <>
6306EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf pcmp_lt_or_nan(const Packet4hf& a, const Packet4hf& b) {
6307 return vreinterpret_f16_u16(vmovn_u32(vmvnq_u32(vcgeq_f32(vcvt_f32_f16(a), vcvt_f32_f16(b)))));
6308}
6309template <>
6310EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf pcmp_lt_or_nan(const Packet8hf& a, const Packet8hf& b) {
6311 return vcombine_f16(pcmp_lt_or_nan(vget_low_f16(a), vget_low_f16(b)),
6312 pcmp_lt_or_nan(vget_high_f16(a), vget_high_f16(b)));
6313}
6314
6315EIGEN_MAKE_HALF_UNOP(print, rndn);
6316EIGEN_MAKE_HALF_UNOP(pfloor, rndm);
6317EIGEN_MAKE_HALF_UNOP(pceil, rndp);
6318EIGEN_MAKE_HALF_UNOP(pround, rnda);
6319EIGEN_MAKE_HALF_UNOP(ptrunc, rnd);
6320
6321#if EIGEN_ARCH_ARM64
6322EIGEN_MAKE_HALF_UNOP(psqrt, sqrt);
6323#else
6324template <>
6325EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf psqrt(const Packet4hf& a) {
6326 return vcvt_f16_f32(psqrt(vcvt_f32_f16(a)));
6327}
6328template <>
6329EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf psqrt(const Packet8hf& a) {
6330 return vcombine_f16(psqrt(vget_low_f16(a)), psqrt(vget_high_f16(a)));
6331}
6332#endif
6333
6334template <>
6335EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf pabs(const Packet8hf& a) {
6336 return vreinterpretq_f16_u16(vbicq_u16(vreinterpretq_u16_f16(a), vdupq_n_u16(0x8000)));
6337}
6338template <>
6339EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf pabs(const Packet4hf& a) {
6340 return vreinterpret_f16_u16(vbic_u16(vreinterpret_u16_f16(a), vdup_n_u16(0x8000)));
6341}
6342
6343// NOTE: On AArch64, we can use horizontal vector reductions for `add`, `min`, and `max`.
6344// However, the fallback through `predux<Packet${N}f>` is still necessary for `mul`.
6345#define EIGEN_HALF_FOLD_REDUX(name, op) \
6346 template <> \
6347 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half name(const Packet4hf& a) { \
6348 return half(name(vcvt_f32_f16(a))); \
6349 } \
6350 template <> \
6351 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half name(const Packet8hf& a) { \
6352 return half(name(p##op(vcvt_f32_f16(vget_low_f16(a)), vcvt_f32_f16(vget_high_f16(a))))); \
6353 } \
6354 static_assert(true, "Trailing semicolon required")
6355
6356#if EIGEN_ARCH_ARM64
6357#define EIGEN_HALF_HORIZONTAL_REDUX(name, op) \
6358 template <> \
6359 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half name(const Packet8hf& a) { \
6360 return half(v##op##vq_f32(v##op##q_f32(vcvt_f32_f16(vget_low_f16(a)), vcvt_f32_f16(vget_high_f16(a))))); \
6361 } \
6362 template <> \
6363 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE half name(const Packet4hf& a) { \
6364 return half(v##op##vq_f32(vcvt_f32_f16(a))); \
6365 } \
6366 static_assert(true, "Trailing semicolon required")
6367#else
6368#define EIGEN_HALF_HORIZONTAL_REDUX(name, op) EIGEN_HALF_FOLD_REDUX(name, op)
6369#endif
6370
6371EIGEN_HALF_HORIZONTAL_REDUX(predux, add);
6372EIGEN_HALF_FOLD_REDUX(predux_mul, mul);
6373EIGEN_HALF_HORIZONTAL_REDUX(predux_min, min);
6374EIGEN_HALF_HORIZONTAL_REDUX(predux_max, max);
6375
6376#undef EIGEN_HALF_FOLD_REDUX
6377#undef EIGEN_HALF_HORIZONTAL_REDUX
6378
6379#undef EIGEN_MAKE_HALF_UNOP
6380#undef EIGEN_MAKE_HALF_BINOP
6381
6382#endif // end EIGEN_HAS_ARM64_FP16_VECTOR_ARITHMETIC
6383
6384#if !EIGEN_HAS_ARM64_FP16_VECTOR_ARITHMETIC
6385// Without FP16 arithmetic, half comparisons convert lane by lane. Classify on the raw bits instead, as for bfloat16:
6386// |a| ==, >, < 0x7c00.
6387EIGEN_STRONG_INLINE uint16x4_t neon_half_abs_bits(const Packet4hf& a) {
6388 return vbic_u16(vreinterpret_u16_f16(a), vdup_n_u16(0x8000));
6389}
6390EIGEN_STRONG_INLINE uint16x8_t neon_half_abs_bits(const Packet8hf& a) {
6391 return vbicq_u16(vreinterpretq_u16_f16(a), vdupq_n_u16(0x8000));
6392}
6393template <>
6394EIGEN_STRONG_INLINE Packet4hf pisinf<Packet4hf>(const Packet4hf& a) {
6395 return vreinterpret_f16_u16(vceq_u16(neon_half_abs_bits(a), vdup_n_u16(0x7c00)));
6396}
6397template <>
6398EIGEN_STRONG_INLINE Packet8hf pisinf<Packet8hf>(const Packet8hf& a) {
6399 return vreinterpretq_f16_u16(vceqq_u16(neon_half_abs_bits(a), vdupq_n_u16(0x7c00)));
6400}
6401template <>
6402EIGEN_STRONG_INLINE Packet4hf pisnan<Packet4hf>(const Packet4hf& a) {
6403 return vreinterpret_f16_u16(vcgt_u16(neon_half_abs_bits(a), vdup_n_u16(0x7c00)));
6404}
6405template <>
6406EIGEN_STRONG_INLINE Packet8hf pisnan<Packet8hf>(const Packet8hf& a) {
6407 return vreinterpretq_f16_u16(vcgtq_u16(neon_half_abs_bits(a), vdupq_n_u16(0x7c00)));
6408}
6409template <>
6410EIGEN_STRONG_INLINE Packet4hf pisfinite<Packet4hf>(const Packet4hf& a) {
6411 return vreinterpret_f16_u16(vclt_u16(neon_half_abs_bits(a), vdup_n_u16(0x7c00)));
6412}
6413template <>
6414EIGEN_STRONG_INLINE Packet8hf pisfinite<Packet8hf>(const Packet8hf& a) {
6415 return vreinterpretq_f16_u16(vcltq_u16(neon_half_abs_bits(a), vdupq_n_u16(0x7c00)));
6416}
6417#endif
6418
6419#define EIGEN_MAKE_HALF_NEG_FMA(name, base, packet) \
6420 template <> \
6421 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE packet name(const packet& a, const packet& b, const packet& c) { \
6422 return pnegate(base(a, b, c)); \
6423 } \
6424 static_assert(true, "Trailing semicolon required")
6425
6426EIGEN_MAKE_HALF_NEG_FMA(pmsub, pnmadd, Packet8hf);
6427EIGEN_MAKE_HALF_NEG_FMA(pmsub, pnmadd, Packet4hf);
6428EIGEN_MAKE_HALF_NEG_FMA(pnmsub, pmadd, Packet8hf);
6429EIGEN_MAKE_HALF_NEG_FMA(pnmsub, pmadd, Packet4hf);
6430
6431#undef EIGEN_MAKE_HALF_NEG_FMA
6432
6433#endif // end EIGEN_ARCH_ARM64 && EIGEN_HAS_ARM64_FP16
6434
6435} // end namespace internal
6436
6437} // end namespace Eigen
6438
6439#endif // EIGEN_PACKET_MATH_NEON_H