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// This Source Code Form is subject to the terms of the Mozilla
5// Public License v. 2.0. If a copy of the MPL was not distributed
6// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
7// SPDX-FileCopyrightText: The Eigen Authors
8// SPDX-License-Identifier: MPL-2.0
9
10#ifndef EIGEN_COMPLEX_SVE_H
11#define EIGEN_COMPLEX_SVE_H
12
13// IWYU pragma: private
14#include "../../InternalHeaderCheck.h"
15
16namespace Eigen {
17namespace internal {
18
19// A complex packet is one real packet holding interleaved {re, im} pairs. That
20// layout is not a choice: GenericPacketMathComplex.h and ConjHelper.h both index
21// the member `v` and construct a complex packet from a real one.
22
23struct PacketXcf {
24 EIGEN_STRONG_INLINE PacketXcf() {}
25 EIGEN_STRONG_INLINE explicit PacketXcf(const PacketXf& a) : v(a) {}
26 PacketXf v;
27};
28
29struct PacketXcd {
30 EIGEN_STRONG_INLINE PacketXcd() {}
31 EIGEN_STRONG_INLINE explicit PacketXcd(const PacketXd& a) : v(a) {}
32 PacketXd v;
33};
34
35template <>
36struct packet_traits<std::complex<float>> : default_packet_traits {
37 typedef PacketXcf type;
38 typedef PacketXcf half;
39 enum {
40 Vectorizable = 1,
41 AlignedOnScalar = 1,
42 size = sve_packet_size_selector<std::complex<float>, EIGEN_ARM64_SVE_VL>::size,
43
44 HasAdd = 1,
45 HasSub = 1,
46 HasMul = 1,
47 HasDiv = 1,
48 HasNegate = 1,
49 HasConj = 1,
50 HasSetLinear = 0,
51 HasAbs = 0,
52 HasAbs2 = 0,
53 HasMin = 0,
54 HasMax = 0,
55 HasArg = 0,
56
57 HasSqrt = 1,
58 HasLog = 1,
59 HasExp = 1
60 };
61};
62
63template <>
64struct packet_traits<std::complex<double>> : default_packet_traits {
65 typedef PacketXcd type;
66 typedef PacketXcd half;
67 enum {
68 Vectorizable = 1,
69 AlignedOnScalar = 1,
70 size = sve_packet_size_selector<std::complex<double>, EIGEN_ARM64_SVE_VL>::size,
71
72 HasAdd = 1,
73 HasSub = 1,
74 HasMul = 1,
75 HasDiv = 1,
76 HasNegate = 1,
77 HasConj = 1,
78 HasSetLinear = 0,
79 HasAbs = 0,
80 HasAbs2 = 0,
81 HasMin = 0,
82 HasMax = 0,
83 HasArg = 0,
84
85 HasSqrt = 1,
86 HasLog = 1,
87 HasExp = 1
88 };
89};
90
91template <>
92struct unpacket_traits<PacketXcf> {
93 typedef std::complex<float> type;
94 typedef PacketXcf half;
95 typedef PacketXf as_real;
96 enum {
97 size = sve_packet_size_selector<std::complex<float>, EIGEN_ARM64_SVE_VL>::size,
98 alignment = sve_packet_alignment_selector<EIGEN_ARM64_SVE_VL>::alignment,
99 vectorizable = true,
100 masked_load_available = false,
101 masked_store_available = false
102 };
103};
104
105template <>
106struct unpacket_traits<PacketXcd> {
107 typedef std::complex<double> type;
108 typedef PacketXcd half;
109 typedef PacketXd as_real;
110 enum {
111 size = sve_packet_size_selector<std::complex<double>, EIGEN_ARM64_SVE_VL>::size,
112 alignment = sve_packet_alignment_selector<EIGEN_ARM64_SVE_VL>::alignment,
113 vectorizable = true,
114 masked_load_available = false,
115 masked_store_available = false
116 };
117};
118
119/********************************* complex<float> *****************************/
120
121template <>
122EIGEN_STRONG_INLINE PacketXcf pset1<PacketXcf>(const std::complex<float>& from) {
123 // {re, im} is one 64-bit lane, so broadcasting the value is a 64-bit dup.
124 return PacketXcf(svreinterpret_f32_u64(svdup_n_u64(numext::bit_cast<numext::uint64_t>(from))));
125}
126
127template <>
128EIGEN_STRONG_INLINE PacketXcf pload<PacketXcf>(const std::complex<float>* from) {
129 return PacketXcf(pload<PacketXf>(reinterpret_cast<const float*>(from)));
130}
131
132template <>
133EIGEN_STRONG_INLINE PacketXcf ploadu<PacketXcf>(const std::complex<float>* from) {
134 return PacketXcf(ploadu<PacketXf>(reinterpret_cast<const float*>(from)));
135}
136
137template <>
138EIGEN_STRONG_INLINE void pstore<std::complex<float>>(std::complex<float>* to, const PacketXcf& from) {
139 pstore(reinterpret_cast<float*>(to), from.v);
140}
141
142template <>
143EIGEN_STRONG_INLINE void pstoreu<std::complex<float>>(std::complex<float>* to, const PacketXcf& from) {
144 pstoreu(reinterpret_cast<float*>(to), from.v);
145}
146
147template <>
148EIGEN_STRONG_INLINE PacketXcf ploaddup<PacketXcf>(const std::complex<float>* from) {
149 // Load the size/2 values this reads into the low half and interleave them
150 // with themselves on 64-bit lanes, which moves whole {re, im} pairs. The
151 // predicate is exact rather than svptrue -- a wider one would read past the
152 // end of the input.
153 constexpr uint64_t kHalf = uint64_t(packet_traits<std::complex<float>>::size) / 2;
154 const svuint64_t lo =
155 svreinterpret_u64_f32(svld1_f32(svwhilelt_b32(uint64_t(0), 2 * kHalf), reinterpret_cast<const float*>(from)));
156 return PacketXcf(svreinterpret_f32_u64(svzip1_u64(lo, lo)));
157}
158
159template <>
160EIGEN_STRONG_INLINE PacketXcf ploadquad<PacketXcf>(const std::complex<float>* from) {
161 // As ploaddup, one zip further: size/4 values, each repeated four times. At
162 // the smallest vector length size/4 rounds to zero, where one value still
163 // has to be read.
164 constexpr uint64_t kQuarter = numext::maxi(uint64_t(packet_traits<std::complex<float>>::size) / 4, uint64_t(1));
165 svuint64_t lo =
166 svreinterpret_u64_f32(svld1_f32(svwhilelt_b32(uint64_t(0), 2 * kQuarter), reinterpret_cast<const float*>(from)));
167 lo = svzip1_u64(lo, lo);
168 return PacketXcf(svreinterpret_f32_u64(svzip1_u64(lo, lo)));
169}
170
171template <>
172EIGEN_STRONG_INLINE PacketXcf pgather<std::complex<float>, PacketXcf>(const std::complex<float>* from, Index stride) {
173 const svuint64_t idx = svindex_u64(0, numext::uint64_t(stride));
174 return PacketXcf(svreinterpret_f32_u64(
175 svld1_gather_u64index_u64(svptrue_b64(), reinterpret_cast<const numext::uint64_t*>(from), idx)));
176}
177
178template <>
179EIGEN_STRONG_INLINE void pscatter<std::complex<float>, PacketXcf>(std::complex<float>* to, const PacketXcf& from,
180 Index stride) {
181 const svuint64_t idx = svindex_u64(0, numext::uint64_t(stride));
182 svst1_scatter_u64index_u64(svptrue_b64(), reinterpret_cast<numext::uint64_t*>(to), idx,
183 svreinterpret_u64_f32(from.v));
184}
185
186template <>
187EIGEN_STRONG_INLINE std::complex<float> pfirst<PacketXcf>(const PacketXcf& a) {
188 // svlasta with no active lane returns lane 0, which is the whole value.
189 return numext::bit_cast<std::complex<float>>(svlasta_u64(svpfalse_b(), svreinterpret_u64_f32(a.v)));
190}
191
192template <>
193EIGEN_STRONG_INLINE PacketXcf pconj(const PacketXcf& a) {
194 // {re, im} is one 64-bit lane with im in the high half, so flipping bit 63
195 // negates the imaginary part alone.
196 return PacketXcf(
197 svreinterpret_f32_u64(sveor_n_u64_x(svptrue_b64(), svreinterpret_u64_f32(a.v), numext::uint64_t(1) << 63)));
198}
199
200template <>
201EIGEN_STRONG_INLINE PacketXcf pcplxflip<PacketXcf>(const PacketXcf& a) {
202 // Swap the 32-bit halves of every 64-bit lane: {re, im} -> {im, re}.
203 return PacketXcf(svreinterpret_f32_u64(svrevw_u64_x(svptrue_b64(), svreinterpret_u64_f32(a.v))));
204}
205
206template <>
207EIGEN_STRONG_INLINE PacketXcf pdupreal<PacketXcf>(const PacketXcf& a) {
208 return PacketXcf(svtrn1_f32(a.v, a.v));
209}
210
211template <>
212EIGEN_STRONG_INLINE PacketXcf pdupimag<PacketXcf>(const PacketXcf& a) {
213 return PacketXcf(svtrn2_f32(a.v, a.v));
214}
215
216template <>
217EIGEN_STRONG_INLINE PacketXcf preverse(const PacketXcf& a) {
218 // Reversing 64-bit lanes moves whole complex values and keeps {re, im} paired.
219 return PacketXcf(svreinterpret_f32_u64(svrev_u64(svreinterpret_u64_f32(a.v))));
220}
221
222template <>
223EIGEN_STRONG_INLINE std::complex<float> predux<PacketXcf>(const PacketXcf& a) {
224 // Read as a 32-bit predicate, an all-true 64-bit one is exactly the even
225 // lanes -- the real parts -- and reversing it gives the odd ones.
226 const svbool_t even = svptrue_b64();
227 const svbool_t odd = svrev_b32(even);
228 return {svaddv_f32(even, a.v), svaddv_f32(odd, a.v)};
229}
230
231/********************************* complex<double> ****************************/
232// A complex<double> spans two 64-bit lanes rather than sitting inside one, so
233// the lane kernels below index components instead of whole values.
234
235template <>
236EIGEN_STRONG_INLINE PacketXcd pset1<PacketXcd>(const std::complex<double>& from) {
237 // A complex value is one 128-bit quadword, so broadcasting it is a quadword dup.
238 return PacketXcd(svdupq_n_f64(numext::real(from), numext::imag(from)));
239}
240
241template <>
242EIGEN_STRONG_INLINE PacketXcd pload<PacketXcd>(const std::complex<double>* from) {
243 return PacketXcd(pload<PacketXd>(reinterpret_cast<const double*>(from)));
244}
245
246template <>
247EIGEN_STRONG_INLINE PacketXcd ploadu<PacketXcd>(const std::complex<double>* from) {
248 return PacketXcd(ploadu<PacketXd>(reinterpret_cast<const double*>(from)));
249}
250
251template <>
252EIGEN_STRONG_INLINE void pstore<std::complex<double>>(std::complex<double>* to, const PacketXcd& from) {
253 pstore(reinterpret_cast<double*>(to), from.v);
254}
255
256template <>
257EIGEN_STRONG_INLINE void pstoreu<std::complex<double>>(std::complex<double>* to, const PacketXcd& from) {
258 pstoreu(reinterpret_cast<double*>(to), from.v);
259}
260
261// Gather the components of complex value `value_index[i]`, keeping the
262// component offset of lane i.
263EIGEN_STRONG_INLINE svuint64_t sve_cd_component_index(const svuint64_t& value_index) {
264 const svuint64_t lane = svindex_u64(0, 1);
265 return svadd_u64_x(svptrue_b64(), svlsl_n_u64_x(svptrue_b64(), value_index, 1),
266 svand_n_u64_x(svptrue_b64(), lane, 1));
267}
268
269// Repeat each of the leading `kValues` complex values `1 << kLog2Repeat` times.
270// Reading them contiguously under an exact predicate and permuting beats a
271// gather, and unlike a 128-bit zip it needs no f64mm: lane j wants component
272// j & 1 of complex value j >> (kLog2Repeat + 1).
273template <int kLog2Repeat>
274EIGEN_STRONG_INLINE PacketXcd sve_cd_loadrepeat(const std::complex<double>* from) {
275 constexpr uint64_t kValues =
276 numext::maxi(uint64_t(packet_traits<std::complex<double>>::size) >> kLog2Repeat, uint64_t(1));
277 const svfloat64_t lo = svld1_f64(svwhilelt_b64(uint64_t(0), 2 * kValues), reinterpret_cast<const double*>(from));
278 const svuint64_t lane = svindex_u64(0, 1);
279 const svuint64_t idx =
280 svorr_u64_x(svptrue_b64(), svlsl_n_u64_x(svptrue_b64(), svlsr_n_u64_x(svptrue_b64(), lane, kLog2Repeat + 1), 1),
281 svand_n_u64_x(svptrue_b64(), lane, 1));
282 return PacketXcd(svtbl_f64(lo, idx));
283}
284
285template <>
286EIGEN_STRONG_INLINE PacketXcd ploaddup<PacketXcd>(const std::complex<double>* from) {
287 return sve_cd_loadrepeat<1>(from);
288}
289
290template <>
291EIGEN_STRONG_INLINE PacketXcd ploadquad<PacketXcd>(const std::complex<double>* from) {
292 return sve_cd_loadrepeat<2>(from);
293}
294
295template <>
296EIGEN_STRONG_INLINE PacketXcd pgather<std::complex<double>, PacketXcd>(const std::complex<double>* from, Index stride) {
297 const svuint64_t value =
298 svmul_n_u64_x(svptrue_b64(), svlsr_n_u64_x(svptrue_b64(), svindex_u64(0, 1), 1), numext::uint64_t(stride));
299 return PacketXcd(
300 svld1_gather_u64index_f64(svptrue_b64(), reinterpret_cast<const double*>(from), sve_cd_component_index(value)));
301}
302
303template <>
304EIGEN_STRONG_INLINE void pscatter<std::complex<double>, PacketXcd>(std::complex<double>* to, const PacketXcd& from,
305 Index stride) {
306 const svuint64_t value =
307 svmul_n_u64_x(svptrue_b64(), svlsr_n_u64_x(svptrue_b64(), svindex_u64(0, 1), 1), numext::uint64_t(stride));
308 svst1_scatter_u64index_f64(svptrue_b64(), reinterpret_cast<double*>(to), sve_cd_component_index(value), from.v);
309}
310
311template <>
312EIGEN_STRONG_INLINE std::complex<double> pfirst<PacketXcd>(const PacketXcd& a) {
313 // svlastb with a VL1 predicate reads lane 0, VL2 reads lane 1.
314 return {svlastb_f64(svptrue_pat_b64(SV_VL1), a.v), svlastb_f64(svptrue_pat_b64(SV_VL2), a.v)};
315}
316
317template <>
318EIGEN_STRONG_INLINE PacketXcd pconj(const PacketXcd& a) {
319 // Flip the sign bit of every odd lane; the mask repeats every quadword.
320 const svuint64_t mask = svdupq_n_u64(0, numext::uint64_t(1) << 63);
321 return PacketXcd(svreinterpret_f64_u64(sveor_u64_x(svptrue_b64(), svreinterpret_u64_f64(a.v), mask)));
322}
323
324template <>
325EIGEN_STRONG_INLINE PacketXcd pcplxflip<PacketXcd>(const PacketXcd& a) {
326 // Swapping the two lanes of each complex value is an index xor 1.
327 return PacketXcd(svtbl_f64(a.v, sveor_n_u64_x(svptrue_b64(), svindex_u64(0, 1), 1)));
328}
329
330template <>
331EIGEN_STRONG_INLINE PacketXcd pdupreal<PacketXcd>(const PacketXcd& a) {
332 return PacketXcd(svtrn1_f64(a.v, a.v));
333}
334
335template <>
336EIGEN_STRONG_INLINE PacketXcd pdupimag<PacketXcd>(const PacketXcd& a) {
337 return PacketXcd(svtrn2_f64(a.v, a.v));
338}
339
340template <>
341EIGEN_STRONG_INLINE PacketXcd preverse(const PacketXcd& a) {
342 // Reversing every lane also swaps re and im inside each value; undo that.
343 return pcplxflip<PacketXcd>(PacketXcd(svrev_f64(a.v)));
344}
345
346template <>
347EIGEN_STRONG_INLINE std::complex<double> predux<PacketXcd>(const PacketXcd& a) {
348 const svbool_t even = svdupq_n_b64(true, false);
349 return {svaddv_f64(even, a.v), svaddv_f64(svrev_b64(even), a.v)};
350}
351
352// A complex<double> is one 128-bit quadword, so transposing complex packets is
353// the real backend's zip network run on quadwords. FEAT_F64MM spells that
354// svzip1q_f64/svzip2q_f64, but armv8.2-a+sve has neither those nor SVE2's
355// two-vector svtbl2, so pick each half with svtbl and merge them on a
356// quadword-alternating predicate. Both index vectors and the predicate are
357// loop-invariant, leaving two svtbl and one svsel per output.
358EIGEN_STRONG_INLINE svbool_t sve_cd_quadword_even() {
359 const svuint64_t quadword = svlsr_n_u64_x(svptrue_b64(), svindex_u64(0, 1), 1);
360 return svcmpeq_n_u64(svptrue_b64(), svand_n_u64_x(svptrue_b64(), quadword, 1), 0);
361}
362
363// Lane j of the low zip takes component j & 1 of quadword j >> 2, from a when
364// its own quadword is even and from b when it is odd; the high zip is the same
365// pattern offset by half the packet.
366EIGEN_STRONG_INLINE svuint64_t sve_cd_zip_index(uint64_t offset) {
367 const svuint64_t lane = svindex_u64(0, 1);
368 const svuint64_t pair = svlsl_n_u64_x(svptrue_b64(), svlsr_n_u64_x(svptrue_b64(), lane, 2), 1);
369 return svadd_n_u64_x(svptrue_b64(), svorr_u64_x(svptrue_b64(), pair, svand_n_u64_x(svptrue_b64(), lane, 1)), offset);
370}
371
372template <int N>
373EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<PacketXcd, N>& kernel) {
374 EIGEN_STATIC_ASSERT((N & (N - 1)) == 0, EIGEN_INTERNAL_ERROR_PLEASE_FILE_A_BUG_REPORT);
375 constexpr uint64_t kLanes = 2 * uint64_t(unpacket_traits<PacketXcd>::size);
376 const svbool_t even = sve_cd_quadword_even();
377 const svuint64_t lo_index = sve_cd_zip_index(0);
378 const svuint64_t hi_index = sve_cd_zip_index(kLanes / 2);
379 for (int stride = N / 2; stride > 0; stride >>= 1) {
380 for (int block = 0; block < N; block += 2 * stride) {
381 for (int k = 0; k < stride; ++k) {
382 const svfloat64_t a = kernel.packet[block + k].v;
383 const svfloat64_t b = kernel.packet[block + k + stride].v;
384 const svfloat64_t lo = svsel_f64(even, svtbl_f64(a, lo_index), svtbl_f64(b, lo_index));
385 const svfloat64_t hi = svsel_f64(even, svtbl_f64(a, hi_index), svtbl_f64(b, hi_index));
386 kernel.packet[block + k] = PacketXcd(lo);
387 kernel.packet[block + k + stride] = PacketXcd(hi);
388 }
389 }
390 }
391}
392
393/********************************* shared *************************************/
394
395// Everything that acts on {re, im} pairs identically forwards to the real packet.
396#define EIGEN_SVE_COMPLEX_DELEGATE(PACKET_CPLX) \
397 template <> \
398 EIGEN_STRONG_INLINE PACKET_CPLX padd<PACKET_CPLX>(const PACKET_CPLX& a, const PACKET_CPLX& b) { \
399 return PACKET_CPLX(padd(a.v, b.v)); \
400 } \
401 template <> \
402 EIGEN_STRONG_INLINE PACKET_CPLX psub<PACKET_CPLX>(const PACKET_CPLX& a, const PACKET_CPLX& b) { \
403 return PACKET_CPLX(psub(a.v, b.v)); \
404 } \
405 template <> \
406 EIGEN_STRONG_INLINE PACKET_CPLX pnegate(const PACKET_CPLX& a) { \
407 return PACKET_CPLX(pnegate(a.v)); \
408 } \
409 template <> \
410 EIGEN_STRONG_INLINE PACKET_CPLX pzero<PACKET_CPLX>(const PACKET_CPLX& a) { \
411 return PACKET_CPLX(pzero(a.v)); \
412 } \
413 template <> \
414 EIGEN_STRONG_INLINE PACKET_CPLX pand<PACKET_CPLX>(const PACKET_CPLX& a, const PACKET_CPLX& b) { \
415 return PACKET_CPLX(pand(a.v, b.v)); \
416 } \
417 template <> \
418 EIGEN_STRONG_INLINE PACKET_CPLX por<PACKET_CPLX>(const PACKET_CPLX& a, const PACKET_CPLX& b) { \
419 return PACKET_CPLX(por(a.v, b.v)); \
420 } \
421 template <> \
422 EIGEN_STRONG_INLINE PACKET_CPLX pxor<PACKET_CPLX>(const PACKET_CPLX& a, const PACKET_CPLX& b) { \
423 return PACKET_CPLX(pxor(a.v, b.v)); \
424 } \
425 template <> \
426 EIGEN_STRONG_INLINE PACKET_CPLX pandnot<PACKET_CPLX>(const PACKET_CPLX& a, const PACKET_CPLX& b) { \
427 return PACKET_CPLX(pandnot(a.v, b.v)); \
428 } \
429 template <> \
430 EIGEN_STRONG_INLINE PACKET_CPLX pselect<PACKET_CPLX>(const PACKET_CPLX& mask, const PACKET_CPLX& a, \
431 const PACKET_CPLX& b) { \
432 return PACKET_CPLX(pselect(mask.v, a.v, b.v)); \
433 } \
434 template <> \
435 EIGEN_STRONG_INLINE PACKET_CPLX pmul<PACKET_CPLX>(const PACKET_CPLX& a, const PACKET_CPLX& b) { \
436 return pmul_complex(a, b); \
437 } \
438 template <> \
439 EIGEN_STRONG_INLINE PACKET_CPLX pdiv<PACKET_CPLX>(const PACKET_CPLX& a, const PACKET_CPLX& b) { \
440 return pdiv_complex(a, b); \
441 } \
442 /* A complex value is equal only if both components are, so fold the two */ \
443 /* real-lane results together across each pair. */ \
444 template <> \
445 EIGEN_STRONG_INLINE PACKET_CPLX pcmp_eq<PACKET_CPLX>(const PACKET_CPLX& a, const PACKET_CPLX& b) { \
446 const PACKET_CPLX t = PACKET_CPLX(pcmp_eq(a.v, b.v)); \
447 return PACKET_CPLX(pand(pdupreal(t).v, pdupimag(t).v)); \
448 }
449
450EIGEN_SVE_COMPLEX_DELEGATE(PacketXcf)
451EIGEN_SVE_COMPLEX_DELEGATE(PacketXcd)
452#undef EIGEN_SVE_COMPLEX_DELEGATE
453
454EIGEN_INSTANTIATE_COMPLEX_MATH_FUNCS(PacketXcf)
455EIGEN_INSTANTIATE_COMPLEX_MATH_FUNCS(PacketXcd)
456
457// A complex value is exactly one 64-bit lane, so transposing complex packets is
458// a zip network run on 64-bit elements.
459template <int N>
460EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<PacketXcf, N>& kernel) {
461 EIGEN_STATIC_ASSERT((N & (N - 1)) == 0, EIGEN_INTERNAL_ERROR_PLEASE_FILE_A_BUG_REPORT);
462 for (int stride = N / 2; stride > 0; stride >>= 1) {
463 for (int block = 0; block < N; block += 2 * stride) {
464 for (int k = 0; k < stride; ++k) {
465 const svuint64_t a = svreinterpret_u64_f32(kernel.packet[block + k].v);
466 const svuint64_t b = svreinterpret_u64_f32(kernel.packet[block + k + stride].v);
467 kernel.packet[block + k] = PacketXcf(svreinterpret_f32_u64(svzip1_u64(a, b)));
468 kernel.packet[block + k + stride] = PacketXcf(svreinterpret_f32_u64(svzip2_u64(a, b)));
469 }
470 }
471 }
472}
473
474EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(PacketXcf, PacketXf)
475EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(PacketXcd, PacketXd)
476
477/*---------------- load/store segment support ----------------*/
478
479// A complex lane is two real lanes, so the predicate is formed over 2 * begin and 2 * count.
480
481template <>
482struct has_packet_segment<PacketXcf> : std::true_type {};
483
484template <>
485inline PacketXcf ploaduSegment<PacketXcf>(const std::complex<float>* from, Index begin, Index count) {
486 return PacketXcf(svld1_f32(sve_segment_predicate_b32(2 * begin, 2 * count), reinterpret_cast<const float*>(from)));
487}
488
489template <>
490inline void pstoreuSegment<std::complex<float>, PacketXcf>(std::complex<float>* to, const PacketXcf& from, Index begin,
491 Index count) {
492 svst1_f32(sve_segment_predicate_b32(2 * begin, 2 * count), reinterpret_cast<float*>(to), from.v);
493}
494
495template <>
496struct has_packet_segment<PacketXcd> : std::true_type {};
497
498template <>
499inline PacketXcd ploaduSegment<PacketXcd>(const std::complex<double>* from, Index begin, Index count) {
500 return PacketXcd(svld1_f64(sve_segment_predicate_b64(2 * begin, 2 * count), reinterpret_cast<const double*>(from)));
501}
502
503template <>
504inline void pstoreuSegment<std::complex<double>, PacketXcd>(std::complex<double>* to, const PacketXcd& from,
505 Index begin, Index count) {
506 svst1_f64(sve_segment_predicate_b64(2 * begin, 2 * count), reinterpret_cast<double*>(to), from.v);
507}
508
509/*---------------- end load/store segment support ----------------*/
510
511} // end namespace internal
512} // end namespace Eigen
513
514#endif // EIGEN_COMPLEX_SVE_H