Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
vectorclass_sve.hpp
Go to the documentation of this file.
1/*
2 * This file is part of Vlasiator.
3 * Copyright 2025 SiPearl
4 *
5 * For details of usage, see the COPYING file and read the "Rules of the Road"
6 * at http://www.physics.helsinki.fi/vlasiator/
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#ifndef VECTORCLASS_SVE_FIXED_H
24#define VECTORCLASS_SVE_FIXED_H
25
26#include <arm_sve.h>
27#include <array>
28#include <cassert>
29#include <cstddef>
30#include <cstdlib>
31#include <initializer_list>
32#include <new>
33#include <type_traits>
34
35#define SVE_INLINE __attribute__((always_inline))
36
37#ifndef _mm_prefetch
38
39// Ideally, we would want to use the __pld or __pldw intrinsic,
40// but afaik they're available only in armclang...
41// This weird switch is to keep compatibility with X86 flags
42template <uint32_t hint>
44 switch (hint) {
45 case /*_MM_HINT_T0*/ 1:
46 __asm__ __volatile__("prfm PLDL1KEEP, [%0]\n" : : "r"(addr) : "memory");
47 break;
48 case /*_MM_HINT_T1*/ 2:
49 __asm__ __volatile__("prfm PLDL2KEEP, [%0]\n" : : "r"(addr) : "memory");
50 break;
51 case /*_MM_HINT_T2*/ 3:
52 __asm__ __volatile__("prfm PLDL3KEEP, [%0]\n" : : "r"(addr) : "memory");
53 break;
54 case /*_MM_HINT_NTA*/ 0:
55 __asm__ __volatile__("prfm PLDL1STRM, [%0]\n" : : "r"(addr) : "memory");
56 break;
57 case /*_MM_HINT_ENTA*/ 4:
58 __asm__ __volatile__("prfm PSTL1KEEP, [%0]\n" : : "r"(addr) : "memory");
59 break;
60 case /*_MM_HINT_ET0*/ 5:
61 __asm__ __volatile__("prfm PSTL1KEEP, [%0]\n" : : "r"(addr) : "memory");
62 break;
63 case /*_MM_HINT_ET1*/ 6:
64 __asm__ __volatile__("prfm PSTL2KEEP, [%0]\n" : : "r"(addr) : "memory");
65 break;
66 case /*_MM_HINT_ET0*/ 7:
67 __asm__ __volatile__("prfm PSTL3KEEP, [%0]\n" : : "r"(addr) : "memory");
68 break;
69 }
70}
71
72#define _mm_prefetch(addr, hint) aarch64_do_prefetch<hint>(addr)
73#endif
74
75#if !defined(CACHE_LINE_SIZE)
76#define CACHE_LINE_SIZE (64)
77#endif
78
79#define SVE_DISPATCH_1ARG(prefix, arg1) \
80 if constexpr (std::is_same_v<T, __fp16>) { \
81 return prefix##_f16(arg1); \
82 } else if constexpr (std::is_same_v<T, __bf16>) { \
83 return prefix##_bf16(arg1); \
84 } else if constexpr (std::is_same_v<T, float>) { \
85 return prefix##_f32(arg1); \
86 } else if constexpr (std::is_same_v<T, double>) { \
87 return prefix##_f64(arg1); \
88 } else if constexpr (std::is_same_v<T, int32_t>) { \
89 return prefix##_s32(arg1); \
90 } else if constexpr (std::is_same_v<T, int64_t>) { \
91 return prefix##_s64(arg1); \
92 } else { \
93 static_assert(false, "Unsupported type for SVE dispatching"); \
94 }
95
96#define SVE_DISPATCH_1ARG_PREDICATED_SFX(prefix, suffix, predicate, arg1) \
97 if constexpr (std::is_same_v<T, __fp16>) { \
98 return prefix##_f16##suffix(predicate, arg1); \
99 } else if constexpr (std::is_same_v<T, __bf16>) { \
100 return prefix##_bf16##suffix(predicate, arg1); \
101 } else if constexpr (std::is_same_v<T, float>) { \
102 return prefix##_f32##suffix(predicate, arg1); \
103 } else if constexpr (std::is_same_v<T, double>) { \
104 return prefix##_f64##suffix(predicate, arg1); \
105 } else if constexpr (std::is_same_v<T, int32_t>) { \
106 return prefix##_s32##suffix(predicate, arg1); \
107 } else if constexpr (std::is_same_v<T, int64_t>) { \
108 return prefix##_s64##suffix(predicate, arg1); \
109 } else { \
110 static_assert(false, "Unsupported type for SVE dispatching"); \
111 }
112
113#define SVE_DISPATCH_2ARG_PREDICATED_SFX(prefix, suffix, predicate, arg1, arg2) \
114 if constexpr (std::is_same_v<T, __fp16>) { \
115 return prefix##_f16##suffix(predicate, arg1, arg2); \
116 } else if constexpr (std::is_same_v<T, __bf16>) { \
117 return prefix##_bf16##suffix(predicate, arg1, arg2); \
118 } else if constexpr (std::is_same_v<T, float>) { \
119 return prefix##_f32##suffix(predicate, arg1, arg2); \
120 } else if constexpr (std::is_same_v<T, double>) { \
121 return prefix##_f64##suffix(predicate, arg1, arg2); \
122 } else if constexpr (std::is_same_v<T, int32_t>) { \
123 return prefix##_s32##suffix(predicate, arg1, arg2); \
124 } else if constexpr (std::is_same_v<T, int64_t>) { \
125 return prefix##_s64##suffix(predicate, arg1, arg2); \
126 } else { \
127 static_assert(false, "Unsupported type for SVE dispatching"); \
128 }
129
130#define SVE_DISPATCH_1ARG_PREDICATED_NOSFX(prefix, predicate, arg1) \
131 if constexpr (std::is_same_v<T, __fp16>) { \
132 return prefix##_f16(predicate, arg1); \
133 } else if constexpr (std::is_same_v<T, __bf16>) { \
134 return prefix##_bf16(predicate, arg1); \
135 } else if constexpr (std::is_same_v<T, float>) { \
136 return prefix##_f32(predicate, arg1); \
137 } else if constexpr (std::is_same_v<T, double>) { \
138 return prefix##_f64(predicate, arg1); \
139 } else if constexpr (std::is_same_v<T, int32_t>) { \
140 return prefix##_s32(predicate, arg1); \
141 } else if constexpr (std::is_same_v<T, int64_t>) { \
142 return prefix##_s64(predicate, arg1); \
143 } else { \
144 static_assert(false, "Unsupported type for SVE dispatching"); \
145 }
146
147#define SVE_DISPATCH_2ARG_PREDICATED_NOSFX(prefix, predicate, arg1, arg2) \
148 if constexpr (std::is_same_v<T, __fp16>) { \
149 return prefix##_f16(predicate, arg1, arg2); \
150 } else if constexpr (std::is_same_v<T, __bf16>) { \
151 return prefix##_bf16(predicate, arg1, arg2); \
152 } else if constexpr (std::is_same_v<T, float>) { \
153 return prefix##_f32(predicate, arg1, arg2); \
154 } else if constexpr (std::is_same_v<T, double>) { \
155 return prefix##_f64(predicate, arg1, arg2); \
156 } else if constexpr (std::is_same_v<T, int32_t>) { \
157 return prefix##_s32(predicate, arg1, arg2); \
158 } else if constexpr (std::is_same_v<T, int64_t>) { \
159 return prefix##_s64(predicate, arg1, arg2); \
160 } else { \
161 static_assert(false, "Unsupported type for SVE dispatching"); \
162 }
163
164namespace sve {
165template <typename T> struct type {
166 using scalar = T;
167};
168
169template <> struct type<__fp16> {
170 using scalar = __fp16;
171 using integral = int16_t;
172 using vec = svfloat16_t __attribute__((arm_sve_vector_bits(__ARM_FEATURE_SVE_BITS)));
173};
174
175template <> struct type<__bf16> {
176 using scalar = __bf16;
177 using vec = svbfloat16_t __attribute__((arm_sve_vector_bits(__ARM_FEATURE_SVE_BITS)));
178};
179
180template <> struct type<float> {
181 using scalar = float;
182 using integral = int32_t;
183 using vec = svfloat32_t __attribute__((arm_sve_vector_bits(__ARM_FEATURE_SVE_BITS)));
184};
185
186template <> struct type<int32_t> {
187 using scalar = int32_t;
188 using integral = int32_t;
189 using vec = svint32_t __attribute__((arm_sve_vector_bits(__ARM_FEATURE_SVE_BITS)));
190};
191
192template <> struct type<double> {
193 using scalar = double;
194 using integral = int64_t;
195 using vec = svfloat64_t __attribute__((arm_sve_vector_bits(__ARM_FEATURE_SVE_BITS)));
196};
197
198template <> struct type<int64_t> {
199 using scalar = int64_t;
200 using integral = int64_t;
201 using vec = svint64_t __attribute__((arm_sve_vector_bits(__ARM_FEATURE_SVE_BITS)));
202};
203
204namespace instructions {
205
206// Yes, I'm aware that there are intrinsics that
207// encapsulate this _dispatch_ across multiple types
208// Also, there are a ton of intrinsics that do not, so for consistency,
209// all the intrinsics that we use have this form.
210
211// Memory Operations
212template <typename T, typename sve_type_t = typename sve::type<T>::vec>
213SVE_INLINE void svst(const svbool_t& predicate, T* location, const sve_type_t& value) {
214 // SVE_DISPATCH_2ARG_PREDICATED_NOSFX(svst1, predicate, location, value);
215 ::svst1(predicate, location, value);
216}
217
218template <typename T, typename sve_type_t = typename sve::type<T>::vec>
219SVE_INLINE sve_type_t svld(const svbool_t& predicate, const T* ptr) {
220 return ::svld1(predicate, ptr);
221}
222
223// Utility Operations
224template <typename T, typename sve_type_t = typename sve::type<T>::vec> SVE_INLINE sve_type_t svdup(T value) {
225 SVE_DISPATCH_1ARG(svdup_n, value);
226}
227
228template <typename T> SVE_INLINE svbool_t svtrue() {
229 if constexpr (sizeof(T) == 2)
230 return svptrue_b16();
231 else if constexpr (sizeof(T) == 4)
232 return svptrue_b32();
233 else if constexpr (sizeof(T) == 8)
234 return svptrue_b64();
235 else
236 static_assert(false, "Unsupported type for SVE dispatching");
237}
238
239template <typename T, typename sve_type_t = typename sve::type<T>::vec>
240SVE_INLINE T svextract(const svbool_t& predicate, const sve_type_t& vec) {
241 SVE_DISPATCH_2ARG_PREDICATED_NOSFX(svclastb_n, predicate, T(0), vec);
242}
243
244template <typename T> SVE_INLINE svbool_t pred_from_index(const std::size_t index) {
245 if constexpr (sizeof(T) == 2) {
246 return svwhilele_b16_s32(0, index);
247 } else if constexpr (sizeof(T) == 4) {
248 return svwhilele_b32_s32(0, index);
249 } else if constexpr (sizeof(T) == 8) {
250 return svwhilele_b64_s64(0, index);
251 } else {
252 static_assert(false, "Unsupported type for SVE dispatching");
253 }
254}
255
256// Logic Operations
257template <typename T, typename sve_type_t = typename sve::type<T>::vec>
258SVE_INLINE sve_type_t svorr(const svbool_t& predicate, const sve_type_t& v1, const sve_type_t& v2) {
259 SVE_DISPATCH_2ARG_PREDICATED_SFX(svorr, _x, predicate, v1, v2);
260}
261
262template <typename T, typename sve_type_t = typename sve::type<T>::vec>
263SVE_INLINE sve_type_t svsqrt(const svbool_t& predicate, const sve_type_t& v1) {
264 SVE_DISPATCH_1ARG_PREDICATED_SFX(svsqrt, _x, predicate, v1);
265}
266
267template <typename T, typename sve_type_t = typename sve::type<T>::vec>
268SVE_INLINE sve_type_t svand(const svbool_t& predicate, const sve_type_t& v1, const sve_type_t& v2) {
269 SVE_DISPATCH_2ARG_PREDICATED_SFX(svand, _x, predicate, v1, v2);
270}
271
272template <typename T, typename sve_type_t = typename sve::type<T>::vec>
273SVE_INLINE svbool_t sveq(const svbool_t& mask, const sve_type_t& v1, const sve_type_t& v2) {
274 SVE_DISPATCH_2ARG_PREDICATED_NOSFX(svcmpeq, mask, v1, v2);
275}
276
277// Math Operations
278template <typename T, typename sve_type_t = typename sve::type<T>::vec>
279SVE_INLINE sve_type_t svadd(const svbool_t& predicate, const sve_type_t& lhs, const sve_type_t& rhs) {
280 SVE_DISPATCH_2ARG_PREDICATED_SFX(svadd, _x, predicate, lhs, rhs);
281}
282
283template <typename T, typename sve_type_t = typename sve::type<T>::vec>
284SVE_INLINE sve_type_t svadd_n(const svbool_t& predicate, const sve_type_t& lhs, const T rhs) {
285 SVE_DISPATCH_2ARG_PREDICATED_SFX(svadd_n, _m, predicate, lhs, rhs);
286}
287
288template <typename T, typename sve_type_t = typename sve::type<T>::vec>
289SVE_INLINE T reduce(const svbool_t& predicate, const sve_type_t& vec) {
290 SVE_DISPATCH_1ARG_PREDICATED_NOSFX(svaddv, predicate, vec);
291}
292
293template <typename T, typename sve_type_t = typename sve::type<T>::vec>
294SVE_INLINE sve_type_t svmul(const svbool_t& predicate, const sve_type_t& lhs, const sve_type_t& rhs) {
295 SVE_DISPATCH_2ARG_PREDICATED_SFX(svmul, _x, predicate, lhs, rhs);
296}
297
298template <typename T, typename sve_type_t = typename sve::type<T>::vec>
299SVE_INLINE sve_type_t svmul_n(const svbool_t& predicate, const sve_type_t& lhs, const T rhs) {
300 SVE_DISPATCH_2ARG_PREDICATED_SFX(svmul_n, _m, predicate, lhs, rhs);
301}
302
303template <typename T, typename sve_type_t = typename sve::type<T>::vec>
304SVE_INLINE sve_type_t svsub(const svbool_t& predicate, const sve_type_t& lhs, const sve_type_t& rhs) {
305 SVE_DISPATCH_2ARG_PREDICATED_SFX(svsub, _x, predicate, lhs, rhs);
306}
307
308template <typename T, typename sve_type_t = typename sve::type<T>::vec>
309SVE_INLINE sve_type_t svsub_n(const svbool_t& predicate, const sve_type_t& lhs, const T rhs) {
310 SVE_DISPATCH_2ARG_PREDICATED_SFX(svsub_n, _x, predicate, lhs, rhs);
311}
312
313template <typename T, typename sve_type_t = typename sve::type<T>::vec>
314SVE_INLINE sve_type_t svneg(const svbool_t& predicate, const sve_type_t& operand) {
315 SVE_DISPATCH_1ARG_PREDICATED_SFX(svneg, _x, predicate, operand);
316}
317
318template <typename T, typename sve_type_t = typename sve::type<T>::vec>
319SVE_INLINE sve_type_t svdiv(const svbool_t& predicate, const sve_type_t& lhs, const sve_type_t& rhs) {
320 SVE_DISPATCH_2ARG_PREDICATED_SFX(svdiv, _x, predicate, lhs, rhs);
321}
322
323template <typename T, typename sve_type_t = typename sve::type<T>::vec>
324SVE_INLINE sve_type_t svdiv_n(const svbool_t& predicate, const sve_type_t& lhs, const T rhs) {
325 SVE_DISPATCH_2ARG_PREDICATED_SFX(svdiv_n, _x, predicate, lhs, rhs);
326}
327
328template <typename T, typename sve_type_t = typename sve::type<T>::vec>
329SVE_INLINE sve_type_t svabs(const svbool_t& predicate, const sve_type_t& operand) {
330 SVE_DISPATCH_1ARG_PREDICATED_SFX(svabs, _x, predicate, operand);
331}
332
333// Comparison Operations
334template <typename T, typename sve_type_t = typename sve::type<T>::vec>
335SVE_INLINE svbool_t eq(const svbool_t& predicate, const sve_type_t& lhs, const sve_type_t& rhs) {
336 SVE_DISPATCH_2ARG_PREDICATED_NOSFX(svcmpeq, predicate, lhs, rhs);
337}
338
339template <typename T, typename sve_type_t = typename sve::type<T>::vec>
340SVE_INLINE svbool_t neq(const svbool_t& predicate, const sve_type_t& lhs, const sve_type_t& rhs) {
341 SVE_DISPATCH_2ARG_PREDICATED_NOSFX(svcmpne, predicate, lhs, rhs);
342}
343
344template <typename T, typename sve_type_t = typename sve::type<T>::vec>
345SVE_INLINE svbool_t eq_n(const svbool_t& predicate, const sve_type_t& lhs, const T rhs) {
346 SVE_DISPATCH_2ARG_PREDICATED_NOSFX(svcmpeq_n, predicate, lhs, rhs);
347}
348
349template <typename T, typename sve_type_t = typename sve::type<T>::vec>
350SVE_INLINE svbool_t neq_n(const svbool_t& predicate, const sve_type_t& lhs, const T rhs) {
351 SVE_DISPATCH_2ARG_PREDICATED_NOSFX(svcmpne_n, predicate, lhs, rhs);
352}
353
354template <typename T, typename sve_type_t = typename sve::type<T>::vec>
355SVE_INLINE svbool_t lt(const svbool_t& predicate, const sve_type_t& lhs, const sve_type_t& rhs) {
356 SVE_DISPATCH_2ARG_PREDICATED_NOSFX(svcmplt, predicate, lhs, rhs);
357}
358
359template <typename T, typename sve_type_t = typename sve::type<T>::vec>
360SVE_INLINE svbool_t lt_n(const svbool_t& predicate, const sve_type_t& lhs, const T rhs) {
361 SVE_DISPATCH_2ARG_PREDICATED_NOSFX(svcmplt_n, predicate, lhs, rhs);
362}
363
364template <typename T, typename sve_type_t = typename sve::type<T>::vec>
365SVE_INLINE svbool_t leq(const svbool_t& predicate, const sve_type_t& lhs, const sve_type_t& rhs) {
366 SVE_DISPATCH_2ARG_PREDICATED_NOSFX(svcmple, predicate, lhs, rhs);
367}
368
369template <typename T, typename sve_type_t = typename sve::type<T>::vec>
370SVE_INLINE svbool_t leq_n(const svbool_t& predicate, const sve_type_t& lhs, const T rhs) {
371 SVE_DISPATCH_2ARG_PREDICATED_NOSFX(svcmple_n, predicate, lhs, rhs);
372}
373
374template <typename T, typename sve_type_t = typename sve::type<T>::vec>
375SVE_INLINE svbool_t gt(const svbool_t& predicate, const sve_type_t& lhs, const sve_type_t& rhs) {
376 SVE_DISPATCH_2ARG_PREDICATED_NOSFX(svcmpgt, predicate, lhs, rhs);
377}
378
379template <typename T, typename sve_type_t = typename sve::type<T>::vec>
380SVE_INLINE svbool_t gt_n(const svbool_t& predicate, const sve_type_t& lhs, const T rhs) {
381 SVE_DISPATCH_2ARG_PREDICATED_NOSFX(svcmpgt_n, predicate, lhs, rhs);
382}
383
384template <typename T, typename sve_type_t = typename sve::type<T>::vec>
385SVE_INLINE svbool_t geq(const svbool_t& predicate, const sve_type_t& lhs, const sve_type_t& rhs) {
386 SVE_DISPATCH_2ARG_PREDICATED_NOSFX(svcmpge, predicate, lhs, rhs);
387}
388
389template <typename T, typename sve_type_t = typename sve::type<T>::vec>
390SVE_INLINE svbool_t geq_n(const svbool_t& predicate, const sve_type_t& lhs, const T rhs) {
391 SVE_DISPATCH_2ARG_PREDICATED_NOSFX(svcmpge_n, predicate, lhs, rhs);
392}
393
394template <typename T, typename sve_type_t = typename sve::type<T>::vec>
395SVE_INLINE sve_type_t svsel(const svbool_t& predicate, const sve_type_t& lhs, const sve_type_t& rhs) {
396 SVE_DISPATCH_2ARG_PREDICATED_NOSFX(svsel, predicate, lhs, rhs);
397}
398
399// Min and Max
400template <typename T, typename sve_type_t = typename sve::type<T>::vec>
401SVE_INLINE sve_type_t svmin(const svbool_t& predicate, const sve_type_t& lhs, const sve_type_t& rhs) {
402 SVE_DISPATCH_2ARG_PREDICATED_SFX(svmin, _x, predicate, lhs, rhs);
403}
404
405template <typename T, typename sve_type_t = typename sve::type<T>::vec>
406SVE_INLINE sve_type_t svmax(const svbool_t& predicate, const sve_type_t& lhs, const sve_type_t& rhs) {
407 SVE_DISPATCH_2ARG_PREDICATED_SFX(svmax, _x, predicate, lhs, rhs);
408}
409} // namespace instructions
410
411namespace functions {
412
413template <typename sve_wrapper_vector_t, typename predicate_t, typename lhs_sve_vector_t, typename rhs_sve_vector_t,
414 std::size_t len, typename return_sve_vector_t = typename sve_wrapper_vector_t::sve_vec_t>
415sve_wrapper_vector_t transform(const predicate_t& predicate, const lhs_sve_vector_t* lhs, const rhs_sve_vector_t* rhs,
416 return_sve_vector_t (*binary_operation)(const svbool_t&, const lhs_sve_vector_t&,
417 const rhs_sve_vector_t&)) {
418 return_sve_vector_t ret[len];
419
420 for (std::size_t i = 0; i < len; ++i) {
421 ret[i] = binary_operation(predicate.at(i), lhs[i], rhs[i]);
422 }
423 return sve_wrapper_vector_t(ret);
424}
425
426template <typename sve_wrapper_vector_t, typename lhs_sve_vector_t, typename rhs_sve_vector_t, std::size_t len,
427 typename return_sve_vector_t = typename sve_wrapper_vector_t::sve_vec_t>
428sve_wrapper_vector_t transform(const lhs_sve_vector_t* lhs, const rhs_sve_vector_t* rhs,
429 return_sve_vector_t (*binary_operation)(const svbool_t&, const lhs_sve_vector_t&,
430 const rhs_sve_vector_t&)) {
431 return_sve_vector_t ret[len];
433
434 for (std::size_t i = 0; i < len; ++i) {
435 ret[i] = binary_operation(all_lanes, lhs[i], rhs[i]);
436 }
437 return sve_wrapper_vector_t(ret);
438}
439
440template <typename sve_wrapper_vector_t, typename lhs_sve_vector_t, std::size_t len,
441 typename return_sve_vector_t = typename sve_wrapper_vector_t::sve_vec_t,
442 typename scalar_t = typename sve_wrapper_vector_t::sve_scalar_t>
443sve_wrapper_vector_t transform(const lhs_sve_vector_t* lhs, const scalar_t rhs,
444 return_sve_vector_t (*binary_operation_with_scalar)(const svbool_t&,
445 const lhs_sve_vector_t&,
446 const scalar_t)) {
447 return_sve_vector_t ret[len];
449
450 for (std::size_t i = 0; i < len; ++i) {
451 ret[i] = binary_operation_with_scalar(all_lanes, lhs[i], rhs);
452 }
453 return sve_wrapper_vector_t(ret);
454}
455
456template <typename sve_wrapper_vector_t, typename operand_vector_t, std::size_t len,
457 typename return_sve_vector_t = typename sve_wrapper_vector_t::sve_vec_t>
458sve_wrapper_vector_t transform(const operand_vector_t* operand,
459 return_sve_vector_t (*unary_operation)(const svbool_t&, const operand_vector_t&)) {
460 return_sve_vector_t ret[len];
462
463 for (std::size_t i = 0; i < len; ++i) {
464 ret[i] = unary_operation(all_lanes, operand[i]);
465 }
466 return sve_wrapper_vector_t(ret);
467}
468
469template <typename sve_wrapper_vector_t, typename predicate_t, typename lhs_sve_vector_t, std::size_t len,
470 typename return_sve_vector_t = typename sve_wrapper_vector_t::sve_vec_t>
471sve_wrapper_vector_t transform(const lhs_sve_vector_t* operand, const predicate_t* predicate,
472 return_sve_vector_t (*unary_operation)(const svbool_t&, const lhs_sve_vector_t&)) {
473 return_sve_vector_t ret[len];
474
475 for (std::size_t i = 0; i < len; ++i) {
476 ret[i] = unary_operation(predicate[i], operand[i]);
477 }
478 return sve_wrapper_vector_t(ret);
479}
480
481// Version for boolean ops
482template <typename sve_wrapper_vector_t, typename predicate_t, typename lhs_sve_vector_t, typename rhs_sve_vector_t,
483 std::size_t len, typename return_sve_vector_t = typename sve_wrapper_vector_t::sve_vec_t,
484 typename return_scalar_t = typename sve_wrapper_vector_t::sve_scalar_t>
485sve_wrapper_vector_t transform(const lhs_sve_vector_t* lhs, const rhs_sve_vector_t* rhs, const predicate_t* predicate,
486 svbool_t (*binary_operation)(const svbool_t&, const lhs_sve_vector_t&,
487 const rhs_sve_vector_t&)) {
488 return_sve_vector_t ret[len];
489 auto ones = sve::instructions::svdup(return_scalar_t(1));
490 auto zeroes = sve::instructions::svdup(return_scalar_t(0));
491
492 for (std::size_t i = 0; i < len; ++i) {
493 auto result_mask = binary_operation(predicate[i], lhs[i], rhs[i]);
494 ret[i] = sve::instructions::svsel<return_scalar_t>(result_mask, ones, zeroes);
495 }
496 return sve_wrapper_vector_t(ret);
497}
498
499// Unpredicated
500template <typename sve_wrapper_vector_t, typename lhs_sve_vector_t, typename rhs_sve_vector_t, std::size_t len,
501 typename return_sve_vector_t = typename sve_wrapper_vector_t::sve_vec_t,
502 typename return_scalar_t = typename sve_wrapper_vector_t::sve_scalar_t>
503sve_wrapper_vector_t transform(const lhs_sve_vector_t* lhs, const rhs_sve_vector_t* rhs,
504 svbool_t (*binary_operation)(const svbool_t&, const lhs_sve_vector_t&,
505 const rhs_sve_vector_t&)) {
506 return_sve_vector_t ret[len];
507 auto ones = sve::instructions::svdup(return_scalar_t(1));
508 auto zeroes = sve::instructions::svdup(return_scalar_t(0));
510
511 for (std::size_t i = 0; i < len; ++i) {
512 auto result_mask = binary_operation(all_lanes, lhs[i], rhs[i]);
513 ret[i] = sve::instructions::svsel<return_scalar_t>(result_mask, ones, zeroes);
514 }
515 return sve_wrapper_vector_t(ret);
516}
517
518template <typename sve_wrapper_vector_t, typename lhs_sve_vector_t, std::size_t len,
519 typename scalar_t = typename sve_wrapper_vector_t::sve_scalar_t,
520 typename return_sve_vector_t = typename sve_wrapper_vector_t::sve_vec_t,
521 typename return_scalar_t = typename sve_wrapper_vector_t::sve_scalar_t>
522sve_wrapper_vector_t transform(const lhs_sve_vector_t* lhs, const scalar_t rhs,
523 svbool_t (*binary_operation_with_scalar)(const svbool_t&, const lhs_sve_vector_t&,
524 const scalar_t)) {
525 return_sve_vector_t ret[len];
526 auto ones = sve::instructions::svdup(return_scalar_t(1));
527 auto zeroes = sve::instructions::svdup(return_scalar_t(0));
529
530 for (std::size_t i = 0; i < len; ++i) {
531 auto result_mask = binary_operation_with_scalar(all_lanes, lhs[i], rhs);
532 ret[i] = sve::instructions::svsel<return_scalar_t>(result_mask, ones, zeroes);
533 }
534 return sve_wrapper_vector_t(ret);
535}
536
537template <typename T, std::size_t len, std::size_t stride, typename vec_t = typename sve::type<T>::vec>
538void load_into(vec_t* dst, const T* src) {
539 auto all_lanes = sve::instructions::svtrue<T>();
540 for (std::size_t i = 0; i < len; ++i) {
541 dst[i] = sve::instructions::svld(all_lanes, src + i * stride);
542 }
543}
544
545template <typename T, std::size_t len, std::size_t stride, typename vec_t = typename sve::type<T>::vec>
546void store_into(T* dst, const vec_t* src) {
547 auto all_lanes = sve::instructions::svtrue<T>();
548 for (std::size_t i = 0; i < len; ++i) {
549 sve::instructions::svst(all_lanes, dst + i * stride, src[i]);
550 }
551}
552} // namespace functions
553} // namespace sve
554
555static void no_subnormals() {};
556
557template <typename T, std::size_t N> class VecSVEBase {
558
559public:
560 using sve_vec_t = typename sve::type<T>::vec;
563 static constexpr std::size_t sve_size_bytes = __ARM_FEATURE_SVE_BITS >> 3;
564 static constexpr std::size_t len = N * sizeof(T) / sve_size_bytes;
565 static constexpr std::size_t elems_per_vec = sve_size_bytes / sizeof(T);
566
567protected:
569
570public:
571 T operator[](const std::size_t i) const {
572 auto idx_in_data = i / elems_per_vec;
573 auto idx_in_vec = i % elems_per_vec;
574 auto pred = sve::instructions::pred_from_index<T>(idx_in_vec);
575 auto ret = sve::instructions::svextract<T>(pred, this->m_data[idx_in_data]);
576 return ret;
577 }
578
581 sve_scalar_t sum = 0;
582 for (std::size_t i = 0; i < len; ++i) {
583 sum += sve::instructions::reduce<sve_scalar_t>(all_lanes, this->m_data[i]);
584 }
585 return sum;
586 }
587
589 auto* ptr = reinterpret_cast<sve_scalar_t*>(std::aligned_alloc(CACHE_LINE_SIZE, sizeof(sve_scalar_t) * N));
591 return ptr;
592 }
593};
594
595/*
596 * Mask class, to be used for selecting values from VecSVE.
597 * Ideally, we would want to use a lower precision datatype
598 * However, _mixed_ operations in SVE are very tricky
599 * (they are sparrigly available) and thus it requires conversion.
600 * We prefer to use a bit more memory, for better performance
601 */
602template <typename base_t, std::size_t N>
603class VecSVEMask : public VecSVEBase<typename sve::type<base_t>::integral, N> {
604
606
607public:
610 static constexpr std::size_t len = VecSVEBase<T, N>::len;
611 static constexpr std::size_t elems_per_vec = VecSVEBase<T, N>::elems_per_vec;
612
613 VecSVEMask() = default;
614
616 for (std::size_t i = 0; i < len; ++i) {
617 this->m_data[i] = data[i];
618 }
619 }
620
622
623 SVE_INLINE svbool_t at(std::size_t index) const {
626 auto sve_values = this->m_data[index];
627 return sve::instructions::sveq<sve_scalar_t>(all_lanes, sve_values, ones);
628 }
629
630 SVE_INLINE bool any() const { return this->reduce() != 0; }
631
632 SVE_INLINE bool all() const { return this->reduce() == N; }
633
638
643
645 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support comparison between bf16!");
646 auto all_ones = sve::instructions::svdup(sve_scalar_t(1));
647 auto all_zeros = sve::instructions::svdup(sve_scalar_t(0));
649 sve_vec_t storage[len];
650
651 for (std::size_t i = 0; i < len; ++i)
652 storage[i] = sve::instructions::svsel<sve_scalar_t>(at(i), all_zeros, all_ones);
653
654 return VecSVEMask(storage);
655 }
656};
657
658/*
659 * SVE-backed fixed-size vector
660 * Exactly what it sounds like.
661 */
662template <typename T, std::size_t N> class VecSVE : public VecSVEBase<T, N> {
663
664public:
667 static constexpr std::size_t sve_size_bytes = VecSVEBase<T, N>::sve_size_bytes;
668 static constexpr std::size_t len = VecSVEBase<T, N>::len;
669 static constexpr std::size_t elems_per_vec = VecSVEBase<T, N>::elems_per_vec;
670
671 SVE_INLINE VecSVE() = default;
672
674
676 for (std::size_t i = 0; i < len; ++i) {
677 this->m_data[i] = data[i];
678 }
679 }
680
681 SVE_INLINE VecSVE(const VecSVE& other) {
682 for (std::size_t i = 0; i < len; ++i) {
683 this->m_data[i] = other.m_data[i];
684 }
685 }
686
687 SVE_INLINE VecSVE(std::initializer_list<T> values) {
688 // This is a quirk of VectorclassFallback/Agner's Vectorclass
689 // to allow initialization from an initializer list
690 // with a single value.
691 // It is kept here merely as compatibility.
692 // This behaviour is very much _nonstandard_, if you want this,
693 // use the VecSVE(value) constructor instead.
694 // Also, here, a [[likely]] would be great,
695 // but I'd rather keep C++17 compatibility
696 if (values.size() != 1) {
697 const auto* values_ptr = std::data(values);
698 sve::functions::load_into<T, len, elems_per_vec>(this->m_data, values_ptr);
699 } else {
700 auto sve_value = sve::instructions::svdup(*(values.begin()));
701 for (std::size_t i = 0; i < len; ++i) {
702 this->m_data[i] = sve_value;
703 }
704 }
705 }
706
707 SVE_INLINE VecSVE(const T value) {
708 auto sve_value = sve::instructions::svdup(value);
709 for (std::size_t i = 0; i < len; ++i) {
710 this->m_data[i] = sve_value;
711 }
712 }
713
714 template <typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
715 explicit VecSVE(U value) : VecSVE(T(value)) {}
716
718 for (std::size_t i = 0; i < len; ++i) {
719 this->m_data[i] = other.m_data[i];
720 }
721 return *this;
722 }
723
724 template <typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
725 SVE_INLINE VecSVE& operator=(const U value) {
726 auto data = sve::instructions::svdup(T(value));
727 for (std::size_t i = 0; i < len; ++i) {
728 this->m_data[i] = data;
729 }
730 return *this;
731 }
732
733 SVE_INLINE VecSVE& load(const T* ptr) {
735 return *this;
736 }
737
738 SVE_INLINE VecSVE& load_a(const T* ptr) {
739 const auto* ptr_aligned = static_cast<const T*>(__builtin_assume_aligned(ptr, CACHE_LINE_SIZE));
740 return load(ptr_aligned);
741 }
742
743 SVE_INLINE void store(T* destination) const {
744 sve::functions::store_into<T, len, elems_per_vec>(destination, this->m_data);
745 }
746
747 SVE_INLINE void store_a(T* destination) const {
748 auto* destination_aligned = static_cast<T*>(__builtin_assume_aligned(destination, CACHE_LINE_SIZE));
749 store(destination_aligned);
750 }
751
755
756 template <typename conv_t> VecSVE<conv_t, N> as() const {
757
758 static_assert(sizeof(T) == sizeof(conv_t), "Size should match");
759
760 using sve_conv_vec_t = typename VecSVE<conv_t, N>::sve_vec_t;
761
762 sve_conv_vec_t storage[len];
763 auto all_lanes = sve::instructions::svtrue<conv_t>();
764
765 for (std::size_t i = 0; i < len; ++i) {
766 if constexpr (std::is_same_v<conv_t, float>)
767 storage[i] = svcvt_f32_s32_x(all_lanes, this->m_data[i]);
768 else if constexpr (std::is_same_v<conv_t, double>)
769 storage[i] = svcvt_f64_s64_x(all_lanes, this->m_data[i]);
770 else if constexpr (std::is_same_v<conv_t, int16_t>)
771 storage[i] = svcvt_s16_f16_x(all_lanes, this->m_data[i]);
772 else if constexpr (std::is_same_v<conv_t, int32_t>)
773 storage[i] = svcvt_s32_f32_x(all_lanes, this->m_data[i]);
774 else if constexpr (std::is_same_v<conv_t, int64_t>)
775 storage[i] = svcvt_s64_f64_x(all_lanes, this->m_data[i]);
776 else if constexpr (std::is_same_v<T, __bf16>)
777 static_assert(false, "Cannot cast from bfloat16 vector to s16 vector.");
778 else
779 static_assert(false, "Unsupported conversion!");
780 }
781 return VecSVE<conv_t, N>(storage);
782 }
783
788
792 return *this;
793 }
794
795 template <typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
796 SVE_INLINE VecSVE operator+(const U value) const {
797 auto converted_value = T(value);
798 return sve::functions::transform<VecSVE, sve_vec_t, len>(this->m_data, converted_value,
800 }
801
806
810 return *this;
811 }
812
813 template <typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
814 SVE_INLINE VecSVE operator*(const U value) const {
815 auto converted_value = T(value);
816 return sve::functions::transform<VecSVE, sve_vec_t, len>(this->m_data, converted_value,
818 }
819
824
825 SVE_INLINE VecSVE& operator-=(const VecSVE& rhs) const {
828 return *this;
829 }
830
831 template <typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
832 SVE_INLINE VecSVE operator-(const U value) const {
833 auto converted_value = T(value);
834 return sve::functions::transform<VecSVE, sve_vec_t, len>(this->m_data, converted_value,
836 }
837
839 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support negating a bf16!");
841 }
842
843 SVE_INLINE VecSVE operator/(const VecSVE& rhs) const {
844 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support division between bf16!");
847 }
848
849 SVE_INLINE VecSVE& operator/=(const VecSVE& rhs) const {
850 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support division between bf16!");
853 return *this;
854 }
855
856 template <typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
857 SVE_INLINE VecSVE operator/(const U value) const {
858 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support division between bf16!");
859 auto converted_value = T(value);
860 return sve::functions::transform<VecSVE, sve_vec_t, len>(this->m_data, converted_value,
862 }
863
867
872
877
878 SVE_INLINE VecSVE select(const VecSVEMask<T, N>& mask, const VecSVE& rhs) const {
880 mask, this->m_data, rhs.m_data, sve::instructions::svsel<T>);
881 }
882
884 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support comparison between bf16!");
885 return sve::functions::transform<VecSVEMask<T, N>, sve_vec_t, sve_vec_t, len>(this->m_data, rhs.m_data,
887 }
888
889 template <typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
890 SVE_INLINE VecSVEMask<T, N> operator==(const U& value) const {
891 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support comparison between bf16!");
892 auto rhs = T(value);
894 }
895
897 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support comparison between bf16!");
898 return sve::functions::transform<VecSVEMask<T, N>, sve_vec_t, sve_vec_t, len>(this->m_data, rhs.m_data,
900 }
901
902 template <typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
903 SVE_INLINE VecSVEMask<T, N> operator!=(const U& value) const {
904 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support comparison between bf16!");
905 auto rhs = T(value);
906 return sve::functions::transform<VecSVEMask<T, N>, sve_vec_t, len>(this->m_data, rhs,
908 }
909
911 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support comparison between bf16!");
912 return sve::functions::transform<VecSVEMask<T, N>, sve_vec_t, sve_vec_t, len>(this->m_data, rhs.m_data,
914 }
915
916 template <typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
917 SVE_INLINE VecSVEMask<T, N> operator>(const U& value) const {
918 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support comparison between bf16!");
919 auto rhs = T(value);
921 }
922
924 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support comparison between bf16!");
925 return sve::functions::transform<VecSVEMask<T, N>, sve_vec_t, sve_vec_t, len>(this->m_data, rhs.m_data,
927 }
928
929 template <typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
930 SVE_INLINE VecSVEMask<T, N> operator<(const U& value) const {
931 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support comparison between bf16!");
932 auto rhs = T(value);
934 }
935
937 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support comparison between bf16!");
938 return sve::functions::transform<VecSVEMask<T, N>, sve_vec_t, sve_vec_t, len>(this->m_data, rhs.m_data,
940 }
941
942 template <typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
943 SVE_INLINE VecSVEMask<T, N> operator>=(const U& value) const {
944 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support comparison between bf16!");
945 auto rhs = T(value);
946 return sve::functions::transform<VecSVEMask<T, N>, sve_vec_t, len>(this->m_data, rhs,
948 }
949
951 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support comparison between bf16!");
952 return sve::functions::transform<VecSVEMask<T, N>, sve_vec_t, sve_vec_t, len>(this->m_data, rhs.m_data,
954 }
955
956 template <typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
957 SVE_INLINE VecSVEMask<T, N> operator<=(const U& value) const {
958 static_assert(!std::is_same_v<T, __bf16>, "Did you know? SVE doesn't support comparison between bf16!");
959 auto rhs = T(value);
960 return sve::functions::transform<VecSVEMask<T, N>, sve_vec_t, len>(this->m_data, rhs,
962 }
963};
964
965// Support functions
966template <typename T, std::size_t N> SVE_INLINE VecSVE<T, N> abs(const VecSVE<T, N>& v) { return v.abs(); }
967
968template <typename T, std::size_t N> SVE_INLINE VecSVE<T, N> sqrt(const VecSVE<T, N>& v) { return v.sqrt(); }
969
970template <typename T, std::size_t N>
972 return v1.select(mask, v2);
973}
974
975template <typename T, std::size_t N, typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
976SVE_INLINE VecSVE<T, N> select(const VecSVEMask<T, N>& mask, const VecSVE<T, N>& v1, const U value) {
977 // svsel doesn't have a _n option to select against a value
978 // so we gotta create a new vector instead...
979 auto v2 = VecSVE<T, N>(value);
980 return v1.select(mask, v2);
981}
982
983template <typename T, std::size_t N, typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
984SVE_INLINE VecSVE<T, N> select(const VecSVEMask<T, N>& mask, const U value, const VecSVE<T, N>& v1) {
985 // svsel doesn't have a _n option to select against a value
986 // so we gotta create a new vector instead...
987 auto v2 = VecSVE<T, N>(value);
988 return v1.select(mask, v2);
989}
990
991template <typename T, std::size_t N> SVE_INLINE VecSVE<T, N> min(const VecSVE<T, N>& lhs, const VecSVE<T, N>& rhs) {
992 return lhs.min(rhs);
993}
994
995template <typename T, std::size_t N> SVE_INLINE VecSVE<T, N> max(const VecSVE<T, N>& lhs, const VecSVE<T, N>& rhs) {
996 return lhs.max(rhs);
997}
998
999template <typename T, std::size_t N> SVE_INLINE bool horizontal_or(const VecSVEMask<T, N>& vec) { return vec.any(); }
1000
1001template <typename T, std::size_t N> SVE_INLINE bool horizontal_and(const VecSVEMask<T, N>& vec) { return vec.all(); }
1002
1003template <typename other_t, std::size_t N> VecSVE<float, N> to_float(const VecSVE<other_t, N>& vec) {
1004 return vec.template as<float>();
1005}
1006
1007template <typename other_t, std::size_t N> VecSVE<double, N> to_double(const VecSVE<other_t, N>& vec) {
1008 return vec.template as<double>();
1009}
1010
1011template <typename real_t, std::size_t N, typename integral_t = typename sve::type<real_t>::integral>
1013 return arg.template as<integral_t>();
1014}
1015
1016template <typename real_t, std::size_t N, typename integral_t = typename sve::type<real_t>::integral>
1018 auto res = arg + real_t(0.5);
1019 return arg.template as<integral_t>();
1020}
1021
1022template <typename T, std::size_t N> VecSVE<T, N> floor(const VecSVE<T, N>& arg) { return arg; }
1023
1024template <typename T, std::size_t N> T horizontal_add(const VecSVE<T, N>& vec) { return vec.reduce(); }
1025
1026// Symmetric operators, because thanks C++ /s
1027template <typename T, std::size_t N, typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
1028VecSVE<T, N> operator+(const U lhs, const VecSVE<T, N>& rhs) {
1029 return rhs + lhs;
1030}
1031
1032template <typename T, std::size_t N, typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
1033VecSVE<T, N> operator*(const U lhs, const VecSVE<T, N>& rhs) {
1034 return rhs * lhs;
1035}
1036
1037template <typename T, std::size_t N, typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
1039 return rhs - lhs;
1040}
1041
1042template <typename T, std::size_t N, typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
1044 return rhs / lhs;
1045}
1046
1047#endif // VECTORCLASS_SVE_FIXED_H
for i
Definition Dispersion.m:24
typename sve::type< T >::scalar sve_scalar_t
T operator[](const std::size_t i) const
static constexpr std::size_t elems_per_vec
static constexpr std::size_t len
sve_scalar_t * leak_ptr() const
typename sve::type< T >::integral sve_integral_t
sve_vec_t m_data[len] __attribute__((aligned(CACHE_LINE_SIZE)))
typename sve::type< T >::vec sve_vec_t
static constexpr std::size_t sve_size_bytes
SVE_INLINE sve_scalar_t reduce() const
SVE_INLINE VecSVE & operator*=(const VecSVE &rhs)
SVE_INLINE VecSVE max(const VecSVE &rhs) const
SVE_INLINE VecSVE(const T value)
SVE_INLINE VecSVEMask< T, N > operator!=(const U &value) const
static constexpr std::size_t elems_per_vec
SVE_INLINE VecSVEMask< T, N > operator>(const VecSVE &rhs) const
SVE_INLINE VecSVEMask< T, N > operator<=(const U &value) const
SVE_INLINE VecSVE & load_a(const T *ptr)
SVE_INLINE void store_a(T *destination) const
SVE_INLINE VecSVE operator*(const VecSVE &rhs) const
SVE_INLINE VecSVE abs() const
SVE_INLINE VecSVE(sve_vec_t *data)
static constexpr std::size_t len
VecSVE(U value)
SVE_INLINE VecSVE operator-(const U value) const
SVE_INLINE VecSVE operator/(const U value) const
SVE_INLINE VecSVEMask< T, N > operator==(const U &value) const
SVE_INLINE VecSVE(const VecSVE &other)
SVE_INLINE void store(T *destination) const
SVE_INLINE VecSVE(const T *data)
SVE_INLINE VecSVE & load(const T *ptr)
SVE_INLINE VecSVEMask< T, N > operator<(const VecSVE &rhs) const
SVE_INLINE VecSVE min(const VecSVE &rhs) const
SVE_INLINE VecSVE operator-(const VecSVE &rhs) const
SVE_INLINE VecSVE & operator/=(const VecSVE &rhs) const
SVE_INLINE VecSVE select(const VecSVEMask< T, N > &mask, const VecSVE &rhs) const
SVE_INLINE VecSVE & operator=(const VecSVE< T, N > &other)
SVE_INLINE VecSVE operator*(const U value) const
SVE_INLINE VecSVEMask< T, N > operator==(const VecSVE &rhs) const
SVE_INLINE VecSVE operator+(const VecSVE &rhs) const
SVE_INLINE VecSVE & operator=(const U value)
VecSVE< conv_t, N > as() const
SVE_INLINE VecSVE operator-() const
SVE_INLINE VecSVE & operator+=(const VecSVE &rhs)
SVE_INLINE VecSVE operator/(const VecSVE &rhs) const
SVE_INLINE VecSVEMask< T, N > operator>=(const U &value) const
SVE_INLINE VecSVEMask< T, N > operator<=(const VecSVE &rhs) const
SVE_INLINE VecSVE()=default
SVE_INLINE VecSVE operator+(const U value) const
SVE_INLINE VecSVEMask< T, N > operator<(const U &value) const
SVE_INLINE VecSVE sqrt() const
SVE_INLINE VecSVE(std::initializer_list< T > values)
static constexpr std::size_t sve_size_bytes
SVE_INLINE VecSVEMask< T, N > operator!=(const VecSVE &rhs) const
SVE_INLINE VecSVEMask< T, N > operator>(const U &value) const
SVE_INLINE VecSVE & operator-=(const VecSVE &rhs) const
typename VecSVEBase< T, N >::sve_vec_t sve_vec_t
typename VecSVEBase< T, N >::sve_scalar_t sve_scalar_t
SVE_INLINE VecSVEMask< T, N > operator>=(const VecSVE &rhs) const
static constexpr std::size_t len
SVE_INLINE svbool_t at(std::size_t index) const
typename sve::type< base_t >::integral T
typename VecSVEBase< T, N >::sve_scalar_t sve_scalar_t
SVE_INLINE VecSVEMask operator||(const VecSVEMask &rhs) const
SVE_INLINE VecSVEMask operator!() const
static constexpr std::size_t elems_per_vec
SVE_INLINE VecSVEMask(const T *data)
SVE_INLINE bool all() const
SVE_INLINE VecSVEMask(sve_vec_t *data)
typename VecSVEBase< T, N >::sve_vec_t sve_vec_t
SVE_INLINE bool any() const
SVE_INLINE VecSVEMask operator&&(const VecSVEMask &rhs) const
VecSVEMask()=default
function res
Definition hamming.m:1
#define index(i, j, k)
void load_into(vec_t *dst, const T *src)
sve_wrapper_vector_t transform(const predicate_t &predicate, const lhs_sve_vector_t *lhs, const rhs_sve_vector_t *rhs, return_sve_vector_t(*binary_operation)(const svbool_t &, const lhs_sve_vector_t &, const rhs_sve_vector_t &))
void store_into(T *dst, const vec_t *src)
SVE_INLINE sve_type_t svabs(const svbool_t &predicate, const sve_type_t &operand)
SVE_INLINE svbool_t svtrue()
SVE_INLINE svbool_t gt(const svbool_t &predicate, const sve_type_t &lhs, const sve_type_t &rhs)
SVE_INLINE sve_type_t svadd_n(const svbool_t &predicate, const sve_type_t &lhs, const T rhs)
SVE_INLINE svbool_t leq(const svbool_t &predicate, const sve_type_t &lhs, const sve_type_t &rhs)
SVE_INLINE T svextract(const svbool_t &predicate, const sve_type_t &vec)
SVE_INLINE sve_type_t svdup(T value)
SVE_INLINE sve_type_t svdiv_n(const svbool_t &predicate, const sve_type_t &lhs, const T rhs)
SVE_INLINE sve_type_t svsub_n(const svbool_t &predicate, const sve_type_t &lhs, const T rhs)
SVE_INLINE void svst(const svbool_t &predicate, T *location, const sve_type_t &value)
SVE_INLINE sve_type_t svmul_n(const svbool_t &predicate, const sve_type_t &lhs, const T rhs)
SVE_INLINE sve_type_t svorr(const svbool_t &predicate, const sve_type_t &v1, const sve_type_t &v2)
SVE_INLINE sve_type_t svadd(const svbool_t &predicate, const sve_type_t &lhs, const sve_type_t &rhs)
SVE_INLINE svbool_t eq(const svbool_t &predicate, const sve_type_t &lhs, const sve_type_t &rhs)
SVE_INLINE svbool_t lt_n(const svbool_t &predicate, const sve_type_t &lhs, const T rhs)
SVE_INLINE sve_type_t svsub(const svbool_t &predicate, const sve_type_t &lhs, const sve_type_t &rhs)
SVE_INLINE svbool_t gt_n(const svbool_t &predicate, const sve_type_t &lhs, const T rhs)
SVE_INLINE svbool_t leq_n(const svbool_t &predicate, const sve_type_t &lhs, const T rhs)
SVE_INLINE sve_type_t svmax(const svbool_t &predicate, const sve_type_t &lhs, const sve_type_t &rhs)
SVE_INLINE sve_type_t svmin(const svbool_t &predicate, const sve_type_t &lhs, const sve_type_t &rhs)
SVE_INLINE svbool_t neq(const svbool_t &predicate, const sve_type_t &lhs, const sve_type_t &rhs)
SVE_INLINE svbool_t neq_n(const svbool_t &predicate, const sve_type_t &lhs, const T rhs)
SVE_INLINE svbool_t geq_n(const svbool_t &predicate, const sve_type_t &lhs, const T rhs)
SVE_INLINE sve_type_t svmul(const svbool_t &predicate, const sve_type_t &lhs, const sve_type_t &rhs)
SVE_INLINE svbool_t geq(const svbool_t &predicate, const sve_type_t &lhs, const sve_type_t &rhs)
SVE_INLINE sve_type_t svsel(const svbool_t &predicate, const sve_type_t &lhs, const sve_type_t &rhs)
SVE_INLINE svbool_t pred_from_index(const std::size_t index)
SVE_INLINE T reduce(const svbool_t &predicate, const sve_type_t &vec)
SVE_INLINE sve_type_t svneg(const svbool_t &predicate, const sve_type_t &operand)
SVE_INLINE svbool_t sveq(const svbool_t &mask, const sve_type_t &v1, const sve_type_t &v2)
SVE_INLINE sve_type_t svand(const svbool_t &predicate, const sve_type_t &v1, const sve_type_t &v2)
SVE_INLINE svbool_t eq_n(const svbool_t &predicate, const sve_type_t &lhs, const T rhs)
SVE_INLINE sve_type_t svsqrt(const svbool_t &predicate, const sve_type_t &v1)
SVE_INLINE sve_type_t svld(const svbool_t &predicate, const T *ptr)
SVE_INLINE svbool_t lt(const svbool_t &predicate, const sve_type_t &lhs, const sve_type_t &rhs)
SVE_INLINE sve_type_t svdiv(const svbool_t &predicate, const sve_type_t &lhs, const sve_type_t &rhs)
svbfloat16_t __attribute__((arm_sve_vector_bits(__ARM_FEATURE_SVE_BITS))) vec
svfloat16_t __attribute__((arm_sve_vector_bits(__ARM_FEATURE_SVE_BITS))) vec
svfloat64_t __attribute__((arm_sve_vector_bits(__ARM_FEATURE_SVE_BITS))) vec
svfloat32_t __attribute__((arm_sve_vector_bits(__ARM_FEATURE_SVE_BITS))) vec
svint32_t __attribute__((arm_sve_vector_bits(__ARM_FEATURE_SVE_BITS))) vec
svint64_t __attribute__((arm_sve_vector_bits(__ARM_FEATURE_SVE_BITS))) vec
VecSVE< T, N > operator*(const U lhs, const VecSVE< T, N > &rhs)
SVE_INLINE VecSVE< T, N > min(const VecSVE< T, N > &lhs, const VecSVE< T, N > &rhs)
SVE_INLINE VecSVE< T, N > sqrt(const VecSVE< T, N > &v)
#define SVE_DISPATCH_2ARG_PREDICATED_SFX(prefix, suffix, predicate, arg1, arg2)
SVE_INLINE VecSVE< T, N > select(const VecSVEMask< T, N > &mask, const VecSVE< T, N > &v1, const VecSVE< T, N > &v2)
SVE_INLINE bool horizontal_or(const VecSVEMask< T, N > &vec)
void SVE_INLINE aarch64_do_prefetch(void *addr)
VecSVE< integral_t, N > roundi(const VecSVE< real_t, N > &arg)
static void no_subnormals()
VecSVE< T, N > floor(const VecSVE< T, N > &arg)
VecSVE< float, N > to_float(const VecSVE< other_t, N > &vec)
VecSVE< integral_t, N > truncate_to_int(const VecSVE< real_t, N > &arg)
#define SVE_DISPATCH_1ARG_PREDICATED_NOSFX(prefix, predicate, arg1)
VecSVE< T, N > operator-(U lhs, const VecSVE< T, N > &rhs)
SVE_INLINE bool horizontal_and(const VecSVEMask< T, N > &vec)
#define SVE_INLINE
VecSVE< T, N > operator+(const U lhs, const VecSVE< T, N > &rhs)
#define SVE_DISPATCH_1ARG(prefix, arg1)
VecSVE< double, N > to_double(const VecSVE< other_t, N > &vec)
SVE_INLINE VecSVE< T, N > max(const VecSVE< T, N > &lhs, const VecSVE< T, N > &rhs)
SVE_INLINE VecSVE< T, N > abs(const VecSVE< T, N > &v)
#define SVE_DISPATCH_2ARG_PREDICATED_NOSFX(prefix, predicate, arg1, arg2)
VecSVE< T, N > operator/(U lhs, const VecSVE< T, N > &rhs)
#define CACHE_LINE_SIZE
#define SVE_DISPATCH_1ARG_PREDICATED_SFX(prefix, suffix, predicate, arg1)
T horizontal_add(const VecSVE< T, N > &vec)