Eigen  5.0.1
 
Loading...
Searching...
No Matches
Complex.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2014 Benoit Steiner (benoit.steiner.goog@gmail.com)
5//
6// This Source Code Form is subject to the terms of the Mozilla
7// Public License v. 2.0. If a copy of the MPL was not distributed
8// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9// SPDX-License-Identifier: MPL-2.0
10
11#ifndef EIGEN_COMPLEX_AVX_H
12#define EIGEN_COMPLEX_AVX_H
13
14// IWYU pragma: private
15#include "../../InternalHeaderCheck.h"
16
17namespace Eigen {
18
19namespace internal {
20
21EIGEN_GCC_FAST_MATH_COMPLEX_VECTORIZE_WORKAROUND_PUSH
22
23//---------- float ----------
24struct Packet4cf {
25 EIGEN_STRONG_INLINE Packet4cf() {}
26 EIGEN_STRONG_INLINE explicit Packet4cf(const __m256& a) : v(a) {}
27 __m256 v;
28};
29
30#ifndef EIGEN_VECTORIZE_AVX512
31template <>
32struct packet_traits<std::complex<float> > : default_packet_traits {
33 typedef Packet4cf type;
34 typedef Packet2cf half;
35 enum {
36 Vectorizable = 1,
37 AlignedOnScalar = 1,
38 size = 4,
39
40 HasAdd = 1,
41 HasSub = 1,
42 HasMul = 1,
43 HasDiv = 1,
44 HasNegate = 1,
45 HasSqrt = 1,
46 HasLog = 1,
47 HasExp = 1,
48 HasAbs = 0,
49 HasAbs2 = 0,
50 HasMin = 0,
51 HasMax = 0,
52 HasSetLinear = 0
53 };
54};
55#endif
56
57template <>
58struct unpacket_traits<Packet4cf> {
59 typedef std::complex<float> type;
60 typedef Packet2cf half;
61 typedef Packet8f as_real;
62 enum {
63 size = 4,
64 alignment = Aligned32,
65 vectorizable = true,
66 masked_load_available = false,
67 masked_store_available = false
68 };
69};
70
71template <>
72EIGEN_STRONG_INLINE Packet4cf padd<Packet4cf>(const Packet4cf& a, const Packet4cf& b) {
73 return Packet4cf(_mm256_add_ps(a.v, b.v));
74}
75template <>
76EIGEN_STRONG_INLINE Packet4cf psub<Packet4cf>(const Packet4cf& a, const Packet4cf& b) {
77 return Packet4cf(_mm256_sub_ps(a.v, b.v));
78}
79template <>
80EIGEN_STRONG_INLINE Packet4cf pnegate(const Packet4cf& a) {
81 return Packet4cf(pnegate(a.v));
82}
83template <>
84EIGEN_STRONG_INLINE Packet4cf pconj(const Packet4cf& a) {
85 const __m256 mask = _mm256_castsi256_ps(_mm256_setr_epi32(0x00000000, SIGN_MASK_I32, 0x00000000, SIGN_MASK_I32,
86 0x00000000, SIGN_MASK_I32, 0x00000000, SIGN_MASK_I32));
87 return Packet4cf(_mm256_xor_ps(a.v, mask));
88}
89
90template <>
91EIGEN_STRONG_INLINE Packet4cf pmul(const Packet4cf& a, const Packet4cf& b) {
92 __m256 tmp1 = _mm256_mul_ps(_mm256_movehdup_ps(a.v), _mm256_permute_ps(b.v, _MM_SHUFFLE(2, 3, 0, 1)));
93 __m256 tmp2 = _mm256_moveldup_ps(a.v);
94#ifdef EIGEN_VECTORIZE_FMA
95 __m256 result = _mm256_fmaddsub_ps(tmp2, b.v, tmp1);
96#else
97 __m256 result = _mm256_addsub_ps(_mm256_mul_ps(tmp2, b.v), tmp1);
98#endif
99 return Packet4cf(result);
100}
101
102template <>
103EIGEN_STRONG_INLINE Packet4cf pcmp_eq(const Packet4cf& a, const Packet4cf& b) {
104 __m256 eq = _mm256_cmp_ps(a.v, b.v, _CMP_EQ_OQ);
105 return Packet4cf(_mm256_and_ps(eq, _mm256_permute_ps(eq, 0xb1)));
106}
107
108template <>
109EIGEN_STRONG_INLINE Packet4cf ptrue<Packet4cf>(const Packet4cf& a) {
110 return Packet4cf(ptrue(Packet8f(a.v)));
111}
112template <>
113EIGEN_STRONG_INLINE Packet4cf pand<Packet4cf>(const Packet4cf& a, const Packet4cf& b) {
114 return Packet4cf(_mm256_and_ps(a.v, b.v));
115}
116template <>
117EIGEN_STRONG_INLINE Packet4cf por<Packet4cf>(const Packet4cf& a, const Packet4cf& b) {
118 return Packet4cf(_mm256_or_ps(a.v, b.v));
119}
120template <>
121EIGEN_STRONG_INLINE Packet4cf pxor<Packet4cf>(const Packet4cf& a, const Packet4cf& b) {
122 return Packet4cf(_mm256_xor_ps(a.v, b.v));
123}
124template <>
125EIGEN_STRONG_INLINE Packet4cf pandnot<Packet4cf>(const Packet4cf& a, const Packet4cf& b) {
126 return Packet4cf(_mm256_andnot_ps(b.v, a.v));
127}
128
129template <>
130EIGEN_STRONG_INLINE Packet4cf pload<Packet4cf>(const std::complex<float>* from) {
131 EIGEN_DEBUG_ALIGNED_LOAD return Packet4cf(_mm256_load_ps(&numext::real_ref(*from)));
132}
133template <>
134EIGEN_STRONG_INLINE Packet4cf ploadu<Packet4cf>(const std::complex<float>* from) {
135 EIGEN_DEBUG_UNALIGNED_LOAD return Packet4cf(_mm256_loadu_ps(&numext::real_ref(*from)));
136}
137
138template <>
139EIGEN_STRONG_INLINE Packet4cf pset1<Packet4cf>(const std::complex<float>& from) {
140 // Broadcast one complex<float> (64 bits) to all four 64-bit lanes.
141 // _mm256_set_ps with 8 scalar arguments generates a store-to-load forwarding
142 // sequence (4 × 64-bit stores then a 256-bit load) that causes ~15-cycle stalls
143 // on every call.
144 //
145 // _mm_loadl_epi64 is an 8-byte unaligned load through __m128i* (__may_alias__),
146 // so it is safe regardless of complex<float>'s 4-byte alignment and avoids the
147 // strict-aliasing UB that would arise from casting to double* or int64_t*.
148 const __m128i lo64 = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&from));
149#ifdef EIGEN_VECTORIZE_AVX2
150 return Packet4cf(_mm256_castsi256_ps(_mm256_broadcastq_epi64(lo64)));
151#else
152 // No vpbroadcastq without AVX2: first duplicate the 64-bit complex across both
153 // halves of the 128-bit lane (movedup_pd: {x,_} -> {x,x}), otherwise the upper
154 // complex of each lane stays zeroed by _mm_loadl_epi64. Then vinsertf128 the
155 // filled lane into the high 256-bit lane.
156 const __m128 lo = _mm_castpd_ps(_mm_movedup_pd(_mm_castsi128_pd(lo64)));
157 return Packet4cf(_mm256_insertf128_ps(_mm256_castps128_ps256(lo), lo, 1));
158#endif
159}
160
161template <>
162EIGEN_STRONG_INLINE Packet4cf ploaddup<Packet4cf>(const std::complex<float>* from) {
163 // vbroadcastf128 + vpermilpd, 2 uops: broadcast the 16 bytes holding two
164 // complex<float> into both 128-bit lanes, then duplicate each complex so
165 // the result is {c0, c0, c1, c1}. The load has no alignment requirement;
166 // we cast the source pointer through void* rather than through double*
167 // because alignof(std::complex<float>) == 4 < alignof(double).
168 __m256 bcast = _mm256_broadcast_ps(reinterpret_cast<const __m128*>(static_cast<const void*>(from)));
169 return Packet4cf(_mm256_castpd_ps(_mm256_permute_pd(_mm256_castps_pd(bcast), 3 << 2)));
170}
171
172template <>
173EIGEN_STRONG_INLINE void pstore<std::complex<float> >(std::complex<float>* to, const Packet4cf& from) {
174 EIGEN_DEBUG_ALIGNED_STORE _mm256_store_ps(&numext::real_ref(*to), from.v);
175}
176template <>
177EIGEN_STRONG_INLINE void pstoreu<std::complex<float> >(std::complex<float>* to, const Packet4cf& from) {
178 EIGEN_DEBUG_UNALIGNED_STORE _mm256_storeu_ps(&numext::real_ref(*to), from.v);
179}
180
181template <>
182EIGEN_DEVICE_FUNC inline Packet4cf pgather<std::complex<float>, Packet4cf>(const std::complex<float>* from,
183 Index stride) {
184 return Packet4cf(_mm256_set_ps(std::imag(from[3 * stride]), std::real(from[3 * stride]), std::imag(from[2 * stride]),
185 std::real(from[2 * stride]), std::imag(from[1 * stride]), std::real(from[1 * stride]),
186 std::imag(from[0 * stride]), std::real(from[0 * stride])));
187}
188
189template <>
190EIGEN_DEVICE_FUNC inline void pscatter<std::complex<float>, Packet4cf>(std::complex<float>* to, const Packet4cf& from,
191 Index stride) {
192 __m128 low = _mm256_extractf128_ps(from.v, 0);
193 to[stride * 0] =
194 std::complex<float>(_mm_cvtss_f32(_mm_shuffle_ps(low, low, 0)), _mm_cvtss_f32(_mm_shuffle_ps(low, low, 1)));
195 to[stride * 1] =
196 std::complex<float>(_mm_cvtss_f32(_mm_shuffle_ps(low, low, 2)), _mm_cvtss_f32(_mm_shuffle_ps(low, low, 3)));
197
198 __m128 high = _mm256_extractf128_ps(from.v, 1);
199 to[stride * 2] =
200 std::complex<float>(_mm_cvtss_f32(_mm_shuffle_ps(high, high, 0)), _mm_cvtss_f32(_mm_shuffle_ps(high, high, 1)));
201 to[stride * 3] =
202 std::complex<float>(_mm_cvtss_f32(_mm_shuffle_ps(high, high, 2)), _mm_cvtss_f32(_mm_shuffle_ps(high, high, 3)));
203}
204
205template <>
206EIGEN_STRONG_INLINE std::complex<float> pfirst<Packet4cf>(const Packet4cf& a) {
207 return pfirst(Packet2cf(_mm256_castps256_ps128(a.v)));
208}
209
210template <>
211EIGEN_STRONG_INLINE Packet4cf preverse(const Packet4cf& a) {
212 __m128 low = _mm256_extractf128_ps(a.v, 0);
213 __m128 high = _mm256_extractf128_ps(a.v, 1);
214 __m128d lowd = _mm_castps_pd(low);
215 __m128d highd = _mm_castps_pd(high);
216 low = _mm_castpd_ps(_mm_shuffle_pd(lowd, lowd, 0x1));
217 high = _mm_castpd_ps(_mm_shuffle_pd(highd, highd, 0x1));
218 __m256 result = _mm256_setzero_ps();
219 result = _mm256_insertf128_ps(result, low, 1);
220 result = _mm256_insertf128_ps(result, high, 0);
221 return Packet4cf(result);
222}
223
224template <>
225EIGEN_STRONG_INLINE std::complex<float> predux<Packet4cf>(const Packet4cf& a) {
226 return predux(padd(Packet2cf(_mm256_extractf128_ps(a.v, 0)), Packet2cf(_mm256_extractf128_ps(a.v, 1))));
227}
228
229template <>
230EIGEN_STRONG_INLINE std::complex<float> predux_mul<Packet4cf>(const Packet4cf& a) {
231 return predux_mul(pmul(Packet2cf(_mm256_extractf128_ps(a.v, 0)), Packet2cf(_mm256_extractf128_ps(a.v, 1))));
232}
233
234EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet4cf, Packet8f)
235
236template <>
237EIGEN_STRONG_INLINE Packet4cf pdiv<Packet4cf>(const Packet4cf& a, const Packet4cf& b) {
238 return pdiv_complex(a, b);
239}
240
241template <>
242EIGEN_STRONG_INLINE Packet4cf pcplxflip<Packet4cf>(const Packet4cf& x) {
243 return Packet4cf(_mm256_shuffle_ps(x.v, x.v, _MM_SHUFFLE(2, 3, 0, 1)));
244}
245
246//---------- double ----------
247struct Packet2cd {
248 EIGEN_STRONG_INLINE Packet2cd() {}
249 EIGEN_STRONG_INLINE explicit Packet2cd(const __m256d& a) : v(a) {}
250 __m256d v;
251};
252
253#ifndef EIGEN_VECTORIZE_AVX512
254template <>
255struct packet_traits<std::complex<double> > : default_packet_traits {
256 typedef Packet2cd type;
257 typedef Packet1cd half;
258 enum {
259 Vectorizable = 1,
260 AlignedOnScalar = 0,
261 size = 2,
262
263 HasAdd = 1,
264 HasSub = 1,
265 HasMul = 1,
266 HasDiv = 1,
267 HasNegate = 1,
268 HasSqrt = 1,
269 HasLog = 1,
270 HasExp = 1,
271 HasAbs = 0,
272 HasAbs2 = 0,
273 HasMin = 0,
274 HasMax = 0,
275 HasSetLinear = 0
276 };
277};
278#endif
279
280template <>
281struct unpacket_traits<Packet2cd> {
282 typedef std::complex<double> type;
283 typedef Packet1cd half;
284 typedef Packet4d as_real;
285 enum {
286 size = 2,
287 alignment = Aligned32,
288 vectorizable = true,
289 masked_load_available = false,
290 masked_store_available = false
291 };
292};
293
294template <>
295EIGEN_STRONG_INLINE Packet2cd padd<Packet2cd>(const Packet2cd& a, const Packet2cd& b) {
296 return Packet2cd(_mm256_add_pd(a.v, b.v));
297}
298template <>
299EIGEN_STRONG_INLINE Packet2cd psub<Packet2cd>(const Packet2cd& a, const Packet2cd& b) {
300 return Packet2cd(_mm256_sub_pd(a.v, b.v));
301}
302template <>
303EIGEN_STRONG_INLINE Packet2cd pnegate(const Packet2cd& a) {
304 return Packet2cd(pnegate(a.v));
305}
306template <>
307EIGEN_STRONG_INLINE Packet2cd pconj(const Packet2cd& a) {
308 const __m256d mask =
309 _mm256_castsi256_pd(_mm256_set_epi32(SIGN_MASK_I32, 0x0, 0x0, 0x0, SIGN_MASK_I32, 0x0, 0x0, 0x0));
310 return Packet2cd(_mm256_xor_pd(a.v, mask));
311}
312
313template <>
314EIGEN_STRONG_INLINE Packet2cd pmul(const Packet2cd& a, const Packet2cd& b) {
315 __m256d tmp1 = _mm256_mul_pd(_mm256_permute_pd(a.v, 0xF), _mm256_permute_pd(b.v, 0x5));
316 __m256d tmp2 = _mm256_movedup_pd(a.v);
317#ifdef EIGEN_VECTORIZE_FMA
318 __m256d result = _mm256_fmaddsub_pd(tmp2, b.v, tmp1);
319#else
320 __m256d result = _mm256_addsub_pd(_mm256_mul_pd(tmp2, b.v), tmp1);
321#endif
322 return Packet2cd(result);
323}
324
325template <>
326EIGEN_STRONG_INLINE Packet2cd pcmp_eq(const Packet2cd& a, const Packet2cd& b) {
327 __m256d eq = _mm256_cmp_pd(a.v, b.v, _CMP_EQ_OQ);
328 return Packet2cd(pand(eq, _mm256_permute_pd(eq, 0x5)));
329}
330
331template <>
332EIGEN_STRONG_INLINE Packet2cd ptrue<Packet2cd>(const Packet2cd& a) {
333 return Packet2cd(ptrue(Packet4d(a.v)));
334}
335template <>
336EIGEN_STRONG_INLINE Packet2cd pand<Packet2cd>(const Packet2cd& a, const Packet2cd& b) {
337 return Packet2cd(_mm256_and_pd(a.v, b.v));
338}
339template <>
340EIGEN_STRONG_INLINE Packet2cd por<Packet2cd>(const Packet2cd& a, const Packet2cd& b) {
341 return Packet2cd(_mm256_or_pd(a.v, b.v));
342}
343template <>
344EIGEN_STRONG_INLINE Packet2cd pxor<Packet2cd>(const Packet2cd& a, const Packet2cd& b) {
345 return Packet2cd(_mm256_xor_pd(a.v, b.v));
346}
347template <>
348EIGEN_STRONG_INLINE Packet2cd pandnot<Packet2cd>(const Packet2cd& a, const Packet2cd& b) {
349 return Packet2cd(_mm256_andnot_pd(b.v, a.v));
350}
351
352template <>
353EIGEN_STRONG_INLINE Packet2cd pload<Packet2cd>(const std::complex<double>* from) {
354 EIGEN_DEBUG_ALIGNED_LOAD return Packet2cd(_mm256_load_pd((const double*)from));
355}
356template <>
357EIGEN_STRONG_INLINE Packet2cd ploadu<Packet2cd>(const std::complex<double>* from) {
358 EIGEN_DEBUG_UNALIGNED_LOAD return Packet2cd(_mm256_loadu_pd((const double*)from));
359}
360
361template <>
362EIGEN_STRONG_INLINE Packet2cd pset1<Packet2cd>(const std::complex<double>& from) {
363 // in case casting to a __m128d* is really not safe, then we can still fallback to this version: (much slower though)
364 // return Packet2cd(_mm256_loadu2_m128d((const double*)&from,(const double*)&from));
365 return Packet2cd(_mm256_broadcast_pd((const __m128d*)(const void*)&from));
366}
367
368// The generic ploaddup broadcasts a copy made by pload1_scalar, which keeps GCC from folding
369// the load into vbroadcastf128's memory operand; binding *from directly does not.
370template <>
371EIGEN_STRONG_INLINE Packet2cd ploaddup<Packet2cd>(const std::complex<double>* from) {
372 return pset1<Packet2cd>(*from);
373}
374
375template <>
376EIGEN_STRONG_INLINE void pstore<std::complex<double> >(std::complex<double>* to, const Packet2cd& from) {
377 EIGEN_DEBUG_ALIGNED_STORE _mm256_store_pd((double*)to, from.v);
378}
379template <>
380EIGEN_STRONG_INLINE void pstoreu<std::complex<double> >(std::complex<double>* to, const Packet2cd& from) {
381 EIGEN_DEBUG_UNALIGNED_STORE _mm256_storeu_pd((double*)to, from.v);
382}
383
384template <>
385EIGEN_DEVICE_FUNC inline Packet2cd pgather<std::complex<double>, Packet2cd>(const std::complex<double>* from,
386 Index stride) {
387 return Packet2cd(_mm256_set_pd(std::imag(from[1 * stride]), std::real(from[1 * stride]), std::imag(from[0 * stride]),
388 std::real(from[0 * stride])));
389}
390
391template <>
392EIGEN_DEVICE_FUNC inline void pscatter<std::complex<double>, Packet2cd>(std::complex<double>* to, const Packet2cd& from,
393 Index stride) {
394 __m128d low = _mm256_extractf128_pd(from.v, 0);
395 to[stride * 0] = std::complex<double>(_mm_cvtsd_f64(low), _mm_cvtsd_f64(_mm_shuffle_pd(low, low, 1)));
396 __m128d high = _mm256_extractf128_pd(from.v, 1);
397 to[stride * 1] = std::complex<double>(_mm_cvtsd_f64(high), _mm_cvtsd_f64(_mm_shuffle_pd(high, high, 1)));
398}
399
400template <>
401EIGEN_STRONG_INLINE std::complex<double> pfirst<Packet2cd>(const Packet2cd& a) {
402 __m128d low = _mm256_extractf128_pd(a.v, 0);
403 EIGEN_ALIGN16 double res[2];
404 _mm_store_pd(res, low);
405 return std::complex<double>(res[0], res[1]);
406}
407
408template <>
409EIGEN_STRONG_INLINE Packet2cd preverse(const Packet2cd& a) {
410 __m256d result = _mm256_permute2f128_pd(a.v, a.v, 1);
411 return Packet2cd(result);
412}
413
414template <>
415EIGEN_STRONG_INLINE std::complex<double> predux<Packet2cd>(const Packet2cd& a) {
416 return predux(padd(Packet1cd(_mm256_extractf128_pd(a.v, 0)), Packet1cd(_mm256_extractf128_pd(a.v, 1))));
417}
418
419template <>
420EIGEN_STRONG_INLINE std::complex<double> predux_mul<Packet2cd>(const Packet2cd& a) {
421 return predux(pmul(Packet1cd(_mm256_extractf128_pd(a.v, 0)), Packet1cd(_mm256_extractf128_pd(a.v, 1))));
422}
423
424EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet2cd, Packet4d)
425
426template <>
427EIGEN_STRONG_INLINE Packet2cd pdiv<Packet2cd>(const Packet2cd& a, const Packet2cd& b) {
428 return pdiv_complex(a, b);
429}
430
431template <>
432EIGEN_STRONG_INLINE Packet2cd pcplxflip<Packet2cd>(const Packet2cd& x) {
433 return Packet2cd(_mm256_shuffle_pd(x.v, x.v, 0x5));
434}
435
436EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet4cf, 4>& kernel) {
437 __m256d P0 = _mm256_castps_pd(kernel.packet[0].v);
438 __m256d P1 = _mm256_castps_pd(kernel.packet[1].v);
439 __m256d P2 = _mm256_castps_pd(kernel.packet[2].v);
440 __m256d P3 = _mm256_castps_pd(kernel.packet[3].v);
441
442 __m256d T0 = _mm256_shuffle_pd(P0, P1, 15);
443 __m256d T1 = _mm256_shuffle_pd(P0, P1, 0);
444 __m256d T2 = _mm256_shuffle_pd(P2, P3, 15);
445 __m256d T3 = _mm256_shuffle_pd(P2, P3, 0);
446
447 kernel.packet[1].v = _mm256_castpd_ps(_mm256_permute2f128_pd(T0, T2, 32));
448 kernel.packet[3].v = _mm256_castpd_ps(_mm256_permute2f128_pd(T0, T2, 49));
449 kernel.packet[0].v = _mm256_castpd_ps(_mm256_permute2f128_pd(T1, T3, 32));
450 kernel.packet[2].v = _mm256_castpd_ps(_mm256_permute2f128_pd(T1, T3, 49));
451}
452
453EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet2cd, 2>& kernel) {
454 __m256d tmp = _mm256_permute2f128_pd(kernel.packet[0].v, kernel.packet[1].v, 0 + (2 << 4));
455 kernel.packet[1].v = _mm256_permute2f128_pd(kernel.packet[0].v, kernel.packet[1].v, 1 + (3 << 4));
456 kernel.packet[0].v = tmp;
457}
458
459EIGEN_INSTANTIATE_COMPLEX_MATH_FUNCS_NO_EXP(Packet2cd)
460EIGEN_INSTANTIATE_COMPLEX_MATH_FUNCS(Packet4cf)
461
462template <>
463EIGEN_STRONG_INLINE Packet2cd pexp<Packet2cd>(const Packet2cd& a) {
464#ifdef EIGEN_VECTORIZE_AVX2
465 return pexp_complex<Packet2cd>(a);
466#else
467 // Without AVX2, pexp_complex<Packet2cd> requires psincos_double<Packet4d> which needs
468 // 256-bit integer operations (Packet4l) not available on AVX-only targets.
469 // Process as two independent Packet1cd using the SSE implementation instead.
470 return Packet2cd(_mm256_insertf128_pd(_mm256_castpd128_pd256(pexp(Packet1cd(_mm256_castpd256_pd128(a.v))).v),
471 pexp(Packet1cd(_mm256_extractf128_pd(a.v, 1))).v, 1));
472#endif
473}
474
475#ifdef EIGEN_VECTORIZE_FMA
476// std::complex<float>
477template <>
478EIGEN_STRONG_INLINE Packet4cf pmadd(const Packet4cf& a, const Packet4cf& b, const Packet4cf& c) {
479 __m256 a_odd = _mm256_movehdup_ps(a.v);
480 __m256 a_even = _mm256_moveldup_ps(a.v);
481 __m256 b_swap = _mm256_permute_ps(b.v, _MM_SHUFFLE(2, 3, 0, 1));
482 __m256 result = _mm256_fmaddsub_ps(a_even, b.v, _mm256_fmaddsub_ps(a_odd, b_swap, c.v));
483 return Packet4cf(result);
484}
485template <>
486EIGEN_STRONG_INLINE Packet4cf pmsub(const Packet4cf& a, const Packet4cf& b, const Packet4cf& c) {
487 __m256 a_odd = _mm256_movehdup_ps(a.v);
488 __m256 a_even = _mm256_moveldup_ps(a.v);
489 __m256 b_swap = _mm256_permute_ps(b.v, _MM_SHUFFLE(2, 3, 0, 1));
490 __m256 result = _mm256_fmaddsub_ps(a_even, b.v, _mm256_fmsubadd_ps(a_odd, b_swap, c.v));
491 return Packet4cf(result);
492}
493template <>
494EIGEN_STRONG_INLINE Packet4cf pnmadd(const Packet4cf& a, const Packet4cf& b, const Packet4cf& c) {
495 return pnegate(pmsub(a, b, c));
496}
497template <>
498EIGEN_STRONG_INLINE Packet4cf pnmsub(const Packet4cf& a, const Packet4cf& b, const Packet4cf& c) {
499 return pnegate(pmadd(a, b, c));
500}
501// std::complex<double>
502template <>
503EIGEN_STRONG_INLINE Packet2cd pmadd(const Packet2cd& a, const Packet2cd& b, const Packet2cd& c) {
504 __m256d a_odd = _mm256_permute_pd(a.v, 0xF);
505 __m256d a_even = _mm256_movedup_pd(a.v);
506 __m256d b_swap = _mm256_permute_pd(b.v, 0x5);
507 __m256d result = _mm256_fmaddsub_pd(a_even, b.v, _mm256_fmaddsub_pd(a_odd, b_swap, c.v));
508 return Packet2cd(result);
509}
510template <>
511EIGEN_STRONG_INLINE Packet2cd pmsub(const Packet2cd& a, const Packet2cd& b, const Packet2cd& c) {
512 __m256d a_odd = _mm256_permute_pd(a.v, 0xF);
513 __m256d a_even = _mm256_movedup_pd(a.v);
514 __m256d b_swap = _mm256_permute_pd(b.v, 0x5);
515 __m256d result = _mm256_fmaddsub_pd(a_even, b.v, _mm256_fmsubadd_pd(a_odd, b_swap, c.v));
516 return Packet2cd(result);
517}
518template <>
519EIGEN_STRONG_INLINE Packet2cd pnmadd(const Packet2cd& a, const Packet2cd& b, const Packet2cd& c) {
520 return pnegate(pmsub(a, b, c));
521}
522template <>
523EIGEN_STRONG_INLINE Packet2cd pnmsub(const Packet2cd& a, const Packet2cd& b, const Packet2cd& c) {
524 return pnegate(pmadd(a, b, c));
525}
526#endif
527
528/*---------------- load/store segment support ----------------*/
529
530template <>
531struct has_packet_segment<Packet2cf> : std::true_type {};
532
533template <>
534struct has_packet_segment<Packet4cf> : std::true_type {};
535
536template <>
537struct has_packet_segment<Packet2cd> : std::true_type {};
538
539// With AVX-512VL these packets use k-masked loads and stores instead; see AVX512/Complex.h.
540#ifndef EIGEN_VECTORIZE_AVX512VL
541
542/*---------------- std::complex<float> ----------------*/
543
544template <>
545inline Packet2cf ploaduSegment<Packet2cf>(const std::complex<float>* from, Index begin, Index count) {
546 return (Packet2cf)_mm_maskload_ps(&numext::real_ref(*from), segment_mask_2x64(begin, count));
547}
548
549template <>
550inline void pstoreuSegment<std::complex<float>, Packet2cf>(std::complex<float>* to, const Packet2cf& from, Index begin,
551 Index count) {
552 _mm_maskstore_ps(&numext::real_ref(*to), segment_mask_2x64(begin, count), from.v);
553}
554
555template <>
556inline Packet4cf ploaduSegment<Packet4cf>(const std::complex<float>* from, Index begin, Index count) {
557 return (Packet4cf)_mm256_maskload_ps(&numext::real_ref(*from), segment_mask_4x64(begin, count));
558}
559
560template <>
561inline void pstoreuSegment<std::complex<float>, Packet4cf>(std::complex<float>* to, const Packet4cf& from, Index begin,
562 Index count) {
563 _mm256_maskstore_ps(&numext::real_ref(*to), segment_mask_4x64(begin, count), from.v);
564}
565
566/*---------------- std::complex<double> ----------------*/
567
568template <>
569inline Packet2cd ploaduSegment<Packet2cd>(const std::complex<double>* from, Index begin, Index count) {
570 return (Packet2cd)_mm256_maskload_pd(&numext::real_ref(*from), segment_mask_4x64(2 * begin, 2 * count));
571}
572
573template <>
574inline void pstoreuSegment<std::complex<double>, Packet2cd>(std::complex<double>* to, const Packet2cd& from,
575 Index begin, Index count) {
576 _mm256_maskstore_pd(&numext::real_ref(*to), segment_mask_4x64(2 * begin, 2 * count), from.v);
577}
578
579#endif // EIGEN_VECTORIZE_AVX512VL
580
581/*---------------- end load/store segment support ----------------*/
582
583EIGEN_GCC_FAST_MATH_COMPLEX_VECTORIZE_WORKAROUND_POP
584
585} // end namespace internal
586
587} // end namespace Eigen
588
589#endif // EIGEN_COMPLEX_AVX_H
@ Aligned32
Definition Constants.h:239