HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
simd_intf.hpp
1
2#pragma once
3
4#include "array_generic.hpp"
5#include "half.hpp"
6#include "../macros.hpp"
7#include <cstddef>
8#include <utility>
9#include <tuple>
10#include <concepts>
11
12hi_export_module(hikogui.SIMD.simd_intf);
13
14hi_export namespace hi {
15inline namespace v1 {
16
17template<typename T, std::size_t N>
18struct simd : std::array<T, N> {
19 using array_type = std::array<T, N>;
20 using value_type = T;
21 using generic_type = array_generic<T, N>;
22
23 constexpr simd() noexcept = default;
24 constexpr simd(simd const&) noexcept = default;
25 constexpr simd(simd&&) noexcept = default;
26 constexpr simd& operator=(simd const&) noexcept = default;
27 constexpr simd& operator=(simd&&) noexcept = default;
28
29 template<std::same_as<value_type>... Args>
30 constexpr simd(Args... args) noexcept
31 requires(sizeof...(Args) == N)
32 : array_type(generic_type::set(args...))
33 {
34 }
35
36 constexpr explicit simd(value_type a) noexcept : array_type(generic_type::set(a)) {}
37
38 template<typename O>
39 constexpr simd(std::array<O, N> a) noexcept : array_type(generic_type::convert(a))
40 {
41 }
42
43 [[nodiscard]] constexpr static simd make_undefined() noexcept
44 {
45 return simd{generic_type::undefined()};
46 }
47
48 [[nodiscard]] constexpr static simd make_zero() noexcept
49 {
50 return simd{generic_type::set_zero()};
51 }
52
53 [[nodiscard]] constexpr static simd make_one() noexcept
54 {
55 return simd{generic_type::set_one()};
56 }
57
58 [[nodiscard]] constexpr static simd make_all_ones() noexcept
59 {
60 return simd{generic_type::set_all_ones()};
61 }
62
63 [[nodiscard]] constexpr static simd broadcast(value_type a) noexcept
64 {
65 return simd{generic_type::broadcast(a)};
66 }
67
68 [[nodiscard]] constexpr static simd broadcast(array_type a) noexcept
69 {
70 return simd{generic_type::broadcast(a)};
71 }
72
73 [[nodiscard]] constexpr static simd make_mask(std::size_t mask) noexcept
74 {
75 return simd{generic_type::set_mask(mask)};
76 }
77
78 [[nodiscard]] constexpr std::size_t mask() noexcept
79 {
80 return generic_type::get_mask(*this);
81 }
82
83 [[nodiscard]] constexpr value_type x() const noexcept
84 {
85 return generic_type::template get<0>(*this);
86 }
87
88 [[nodiscard]] constexpr value_type y() const noexcept
89 {
90 return generic_type::template get<1>(*this);
91 }
92
93 [[nodiscard]] constexpr value_type z() const noexcept
94 {
95 return generic_type::template get<2>(*this);
96 }
97
98 [[nodiscard]] constexpr value_type w() const noexcept
99 {
100 return generic_type::template get<3>(*this);
101 }
102
103 [[nodiscard]] constexpr value_type& x() noexcept
104 {
105 return std::get<0>(*this);
106 }
107
108 [[nodiscard]] constexpr value_type& y() noexcept
109 {
110 return std::get<1>(*this);
111 }
112
113 [[nodiscard]] constexpr value_type& z() noexcept
114 {
115 return std::get<2>(*this);
116 }
117
118 [[nodiscard]] constexpr value_type& w() noexcept
119 {
120 return std::get<3>(*this);
121 }
122
123 [[nodiscard]] constexpr value_type r() const noexcept
124 {
125 return generic_type::template get<0>(*this);
126 }
127
128 [[nodiscard]] constexpr value_type g() const noexcept
129 {
130 return generic_type::template get<1>(*this);
131 }
132
133 [[nodiscard]] constexpr value_type b() const noexcept
134 {
135 return generic_type::template get<2>(*this);
136 }
137
138 [[nodiscard]] constexpr value_type a() const noexcept
139 {
140 return generic_type::template get<3>(*this);
141 }
142
143 [[nodiscard]] constexpr value_type& r() noexcept
144 {
145 return std::get<0>(*this);
146 }
147
148 [[nodiscard]] constexpr value_type& g() noexcept
149 {
150 return std::get<1>(*this);
151 }
152
153 [[nodiscard]] constexpr value_type& b() noexcept
154 {
155 return std::get<2>(*this);
156 }
157
158 [[nodiscard]] constexpr value_type& a() noexcept
159 {
160 return std::get<3>(*this);
161 }
162
163 [[nodiscard]] constexpr value_type width() const noexcept
164 {
165 return generic_type::template get<0>(*this);
166 }
167
168 [[nodiscard]] constexpr value_type height() const noexcept
169 {
170 return generic_type::template get<1>(*this);
171 }
172
173 [[nodiscard]] constexpr value_type depth() const noexcept
174 {
175 return generic_type::template get<2>(*this);
176 }
177
178 [[nodiscard]] constexpr value_type& width() noexcept
179 {
180 return std::get<0>(*this);
181 }
182
183 [[nodiscard]] constexpr value_type& height() noexcept
184 {
185 return std::get<1>(*this);
186 }
187
188 [[nodiscard]] constexpr value_type& depth() noexcept
189 {
190 return std::get<2>(*this);
191 }
192
193 [[nodiscard]] constexpr friend simd operator-(array_type a) noexcept
194 {
195 return simd{generic_type::neg(a)};
196 }
197
198 template<std::size_t Mask>
199 [[nodiscard]] constexpr friend simd neg_mask(array_type a) noexcept
200 {
201 return simd{generic_type::template neg_mask<Mask>(a)};
202 }
203
204 [[nodiscard]] constexpr friend simd operator~(array_type a) noexcept
205 {
206 return simd{generic_type::inv(a)};
207 }
208
209 [[nodiscard]] constexpr friend simd rcp(array_type a) noexcept
210 {
211 return simd{generic_type::rcp(a)};
212 }
213
214 [[nodiscard]] constexpr friend simd sqrt(array_type a) noexcept
215 {
216 return simd{generic_type::sqrt(a)};
217 }
218
219 [[nodiscard]] constexpr friend simd rsqrt(array_type a) noexcept
220 {
221 return simd{generic_type::rsqrt(a)};
222 }
223
224 [[nodiscard]] constexpr friend simd abs(array_type a) noexcept
225 {
226 return simd{generic_type::abs(a)};
227 }
228
229 [[nodiscard]] constexpr friend simd round(array_type a) noexcept
230 {
231 return simd{generic_type::round(a)};
232 }
233
234 [[nodiscard]] constexpr friend simd floor(array_type a) noexcept
235 {
236 return simd{generic_type::floor(a)};
237 }
238
239 [[nodiscard]] constexpr friend simd ceil(array_type a) noexcept
240 {
241 return simd{generic_type::ceil(a)};
242 }
243
244 [[nodiscard]] constexpr friend simd operator+(array_type a, array_type b) noexcept
245 {
246 return simd{generic_type::add(a, b)};
247 }
248
249 [[nodiscard]] constexpr friend simd operator-(array_type a, array_type b) noexcept
250 {
251 return simd{generic_type::sub(a, b)};
252 }
253
254 template<std::size_t Mask>
255 [[nodiscard]] constexpr friend simd addsub_mask(array_type a, array_type b) noexcept
256 {
257 return simd{generic_type::template addsub_mask<Mask>(a, b)};
258 }
259
260 [[nodiscard]] constexpr friend simd operator*(array_type a, array_type b) noexcept
261 {
262 return simd{generic_type::mul(a, b)};
263 }
264
265 [[nodiscard]] constexpr friend simd operator/(array_type a, array_type b) noexcept
266 {
267 return simd{generic_type::div(a, b)};
268 }
269
270 [[nodiscard]] constexpr friend simd operator%(array_type a, array_type b) noexcept
271 {
272 return simd{generic_type::mod(a, b)};
273 }
274
275 [[nodiscard]] constexpr friend simd operator==(array_type a, array_type b) noexcept
276 {
277 return simd{generic_type::eq(a, b)};
278 }
279
280 [[nodiscard]] constexpr friend simd operator!=(array_type a, array_type b) noexcept
281 {
282 return simd{generic_type::ne(a, b)};
283 }
284
285 [[nodiscard]] constexpr friend simd operator<(array_type a, array_type b) noexcept
286 {
287 return simd{generic_type::lt(a, b)};
288 }
289
290 [[nodiscard]] constexpr friend simd operator>(array_type a, array_type b) noexcept
291 {
292 return simd{generic_type::gt(a, b)};
293 }
294
295 [[nodiscard]] constexpr friend simd operator<=(array_type a, array_type b) noexcept
296 {
297 return simd{generic_type::le(a, b)};
298 }
299
300 [[nodiscard]] constexpr friend simd operator>=(array_type a, array_type b) noexcept
301 {
302 return simd{generic_type::ge(a, b)};
303 }
304
305 [[nodiscard]] constexpr friend bool test(array_type a, array_type b) noexcept
306 {
307 return generic_type::test(a, b);
308 }
309
310 [[nodiscard]] constexpr friend bool equal(array_type a, array_type b) noexcept
311 {
312 return generic_type::all_equal(a, b);
313 }
314
315 [[nodiscard]] constexpr friend simd max(simd a, simd b) noexcept
316 {
317 return simd{generic_type::max(a, b)};
318 }
319
320 [[nodiscard]] constexpr friend simd min(simd a, simd b) noexcept
321 {
322 return simd{generic_type::min(a, b)};
323 }
324
325 [[nodiscard]] constexpr friend simd clamp(simd v, simd lo, simd hi) noexcept
326 {
327 return simd{generic_type::clamp(v, lo, hi)};
328 }
329
330 [[nodiscard]] constexpr friend simd operator|(array_type a, array_type b) noexcept
331 {
332 return simd{generic_type::_or(a, b)};
333 }
334
335 [[nodiscard]] constexpr friend simd operator&(array_type a, array_type b) noexcept
336 {
337 return simd{generic_type::_and(a, b)};
338 }
339
340 [[nodiscard]] constexpr friend simd operator^(array_type a, array_type b) noexcept
341 {
342 return simd{generic_type::_xor(a, b)};
343 }
344
345 [[nodiscard]] constexpr friend simd sll(array_type a, unsigned int b) noexcept
346 {
347 return simd{generic_type::sll(a, b)};
348 }
349
350 [[nodiscard]] constexpr friend simd sra(array_type a, unsigned int b) noexcept
351 {
352 return simd{generic_type::sra(a, b)};
353 }
354
355 [[nodiscard]] constexpr friend simd srl(array_type a, unsigned int b) noexcept
356 {
357 return simd{generic_type::srl(a, b)};
358 }
359
360 [[nodiscard]] constexpr friend simd operator<<(array_type a, unsigned int b) noexcept
361 {
362 return simd{generic_type::sll(a, b)};
363 }
364
365 [[nodiscard]] constexpr friend simd operator>>(array_type a, unsigned int b) noexcept
366 {
367 if constexpr (std::signed_integral<value_type>) {
368 return simd{generic_type::sra(a, b)};
369 } else {
370 return simd{generic_type::srl(a, b)};
371 }
372 }
373
374 [[nodiscard]] constexpr friend simd andnot(array_type a, array_type b) noexcept
375 {
376 return simd{generic_type::andnot(a, b)};
377 }
378
379 [[nodiscard]] constexpr friend simd hadd(array_type a, array_type b) noexcept
380 {
381 return simd{generic_type::hadd(a, b)};
382 }
383
384 [[nodiscard]] constexpr friend simd hsub(array_type a, array_type b) noexcept
385 {
386 return simd{generic_type::hsub(a, b)};
387 }
388
389 template<int... Indices>
390 [[nodiscard]] constexpr friend simd shuffle(array_type a) noexcept
391 {
392 return simd{generic_type::template shuffle<Indices...>(a)};
393 }
394
395 template<std::size_t Mask>
396 [[nodiscard]] constexpr friend simd blend(array_type a, array_type b) noexcept
397 {
398 return simd{generic_type::template blend<Mask>(a, b)};
399 }
400
401 template<int... Indices>
402 [[nodiscard]] constexpr friend simd swizzle(array_type a) noexcept
403 {
404 return simd{generic_type::template swizzle<Indices...>(a)};
405 }
406
407 [[nodiscard]] constexpr friend simd sum(array_type a) noexcept
408 {
409 return simd{generic_type::sum(a)};
410 }
411
412 template<std::size_t Mask>
413 [[nodiscard]] constexpr friend simd dot(array_type a, array_type b) noexcept
414 {
415 return simd{generic_type::template dot<Mask>(a, b)};
416 }
417
418 template<std::size_t Mask>
419 [[nodiscard]] constexpr friend simd hypot(array_type a) noexcept
420 {
421 return simd{generic_type::template hypot<Mask>(a)};
422 }
423
424 template<std::size_t Mask>
425 [[nodiscard]] constexpr friend simd rhypot(array_type a) noexcept
426 {
427 return simd{generic_type::template rhypot<Mask>(a)};
428 }
429
430 template<std::size_t Mask>
431 [[nodiscard]] constexpr friend simd normalize(array_type a) noexcept
432 {
433 return simd{generic_type::template normalize<Mask>(a)};
434 }
435
436 template<std::derived_from<array_type>... Columns>
437 [[nodiscard]] constexpr friend std::array<simd, N> transpose(Columns... columns) noexcept
438 {
439 auto const tmp = generic_type::template transpose<Columns...>(columns...);
440 auto r = std::array<simd, N>{};
441 for (std::size_t i = 0; i != N; ++i) {
442 r[i] = tmp[i];
443 }
444 return r;
445 }
446
447 constexpr simd& operator+=(array_type a) noexcept
448 {
449 return *this = *this + a;
450 }
451
452 constexpr simd& operator-=(array_type a) noexcept
453 {
454 return *this = *this - a;
455 }
456
457 constexpr simd& operator*=(array_type a) noexcept
458 {
459 return *this = *this * a;
460 }
461
462 constexpr simd& operator/=(array_type a) noexcept
463 {
464 return *this = *this / a;
465 }
466
467 constexpr simd& operator%=(array_type a) noexcept
468 {
469 return *this = *this % a;
470 }
471
472 constexpr simd& operator|=(array_type a) noexcept
473 {
474 return *this = *this | a;
475 }
476
477 constexpr simd& operator&=(array_type a) noexcept
478 {
479 return *this = *this & a;
480 }
481
482 constexpr simd& operator^=(array_type a) noexcept
483 {
484 return *this = *this ^ a;
485 }
486
487#define X_SWIZZLE_2D(NAME, X, Y) \
488 [[nodiscard]] constexpr simd NAME() const noexcept \
489 requires(N == 2) \
490 { \
491 return swizzle<X, Y>(*this); \
492 }
493
494#define X_SWIZZLE_2D_Y(NAME, X) \
495 X_SWIZZLE_2D(NAME##1, X, -2) \
496 X_SWIZZLE_2D(NAME##0, X, -1) \
497 X_SWIZZLE_2D(NAME##x, X, 0) \
498 X_SWIZZLE_2D(NAME##y, X, 1)
499
500 X_SWIZZLE_2D_Y(_1, -2)
501 X_SWIZZLE_2D_Y(_0, -1)
502 X_SWIZZLE_2D_Y(x, 0)
503 X_SWIZZLE_2D_Y(y, 1)
504
505#define X_SWIZZLE_4D(NAME, X, Y, Z, W) \
506 [[nodiscard]] constexpr simd NAME() const noexcept \
507 requires(N == 4) \
508 { \
509 return swizzle<X, Y, Z, W>(*this); \
510 }
511
512#define X_SWIZZLE_4D_W(NAME, X, Y, Z) \
513 X_SWIZZLE_4D(NAME##1, X, Y, Z, -2) \
514 X_SWIZZLE_4D(NAME##0, X, Y, Z, -1) \
515 X_SWIZZLE_4D(NAME##x, X, Y, Z, 0) \
516 X_SWIZZLE_4D(NAME##y, X, Y, Z, 1) \
517 X_SWIZZLE_4D(NAME##z, X, Y, Z, 2) \
518 X_SWIZZLE_4D(NAME##w, X, Y, Z, 3)
519
520#define X_SWIZZLE_4D_Z(NAME, X, Y) \
521 X_SWIZZLE_4D_W(NAME##1, X, Y, -2) \
522 X_SWIZZLE_4D_W(NAME##0, X, Y, -1) \
523 X_SWIZZLE_4D_W(NAME##x, X, Y, 0) \
524 X_SWIZZLE_4D_W(NAME##y, X, Y, 1) \
525 X_SWIZZLE_4D_W(NAME##z, X, Y, 2) \
526 X_SWIZZLE_4D_W(NAME##w, X, Y, 3)
527
528#define X_SWIZZLE_4D_Y(NAME, X) \
529 X_SWIZZLE_4D_Z(NAME##1, X, -2) \
530 X_SWIZZLE_4D_Z(NAME##0, X, -1) \
531 X_SWIZZLE_4D_Z(NAME##x, X, 0) \
532 X_SWIZZLE_4D_Z(NAME##y, X, 1) \
533 X_SWIZZLE_4D_Z(NAME##z, X, 2) \
534 X_SWIZZLE_4D_Z(NAME##w, X, 3)
535
536 X_SWIZZLE_4D_Y(_1, -2)
537 X_SWIZZLE_4D_Y(_0, -1)
538 X_SWIZZLE_4D_Y(x, 0)
539 X_SWIZZLE_4D_Y(y, 1)
540 X_SWIZZLE_4D_Y(z, 2)
541 X_SWIZZLE_4D_Y(w, 3)
542};
543
544using i8x1 = simd<int8_t, 1>;
545using i8x2 = simd<int8_t, 2>;
546using i8x4 = simd<int8_t, 4>;
547using i8x8 = simd<int8_t, 8>;
548using i8x16 = simd<int8_t, 16>;
549using i8x32 = simd<int8_t, 32>;
550using i8x64 = simd<int8_t, 64>;
551
552using u8x1 = simd<uint8_t, 1>;
553using u8x2 = simd<uint8_t, 2>;
554using u8x4 = simd<uint8_t, 4>;
555using u8x8 = simd<uint8_t, 8>;
559
560using i16x1 = simd<int16_t, 1>;
561using i16x2 = simd<int16_t, 2>;
562using i16x4 = simd<int16_t, 4>;
563using i16x8 = simd<int16_t, 8>;
566
573
574using f16x4 = simd<half, 4>;
575
576using i32x1 = simd<int32_t, 1>;
577using i32x2 = simd<int32_t, 2>;
578using i32x4 = simd<int32_t, 4>;
579using i32x8 = simd<int32_t, 8>;
581
587
588using f32x1 = simd<float, 1>;
589using f32x2 = simd<float, 2>;
590using f32x4 = simd<float, 4>;
591using f32x8 = simd<float, 8>;
592using f32x16 = simd<float, 16>;
593
594using i64x1 = simd<int64_t, 1>;
595using i64x2 = simd<int64_t, 2>;
596using i64x4 = simd<int64_t, 4>;
597using i64x8 = simd<int64_t, 8>;
598
603
604using f64x1 = simd<double, 1>;
605using f64x2 = simd<double, 2>;
606using f64x4 = simd<double, 4>;
607using f64x8 = simd<double, 8>;
608
609static_assert(equal(f32x2{2.0f, 3.0f}.xx(), f32x2{2.0f, 2.0f}));
610static_assert(equal(f32x2{2.0f, 3.0f}.xy(), f32x2{2.0f, 3.0f}));
611static_assert(equal(f32x2{2.0f, 3.0f}.x0(), f32x2{2.0f, 0.0f}));
612static_assert(equal(f32x2{2.0f, 3.0f}.x1(), f32x2{2.0f, 1.0f}));
613
614static_assert(equal(f32x2{2.0f, 3.0f}.yx(), f32x2{3.0f, 2.0f}));
615static_assert(equal(f32x2{2.0f, 3.0f}.yy(), f32x2{3.0f, 3.0f}));
616static_assert(equal(f32x2{2.0f, 3.0f}.y0(), f32x2{3.0f, 0.0f}));
617static_assert(equal(f32x2{2.0f, 3.0f}.y1(), f32x2{3.0f, 1.0f}));
618
619static_assert(equal(f32x2{2.0f, 3.0f}._0x(), f32x2{0.0f, 2.0f}));
620static_assert(equal(f32x2{2.0f, 3.0f}._0y(), f32x2{0.0f, 3.0f}));
621static_assert(equal(f32x2{2.0f, 3.0f}._00(), f32x2{0.0f, 0.0f}));
622static_assert(equal(f32x2{2.0f, 3.0f}._01(), f32x2{0.0f, 1.0f}));
623
624static_assert(equal(f32x2{2.0f, 3.0f}._1x(), f32x2{1.0f, 2.0f}));
625static_assert(equal(f32x2{2.0f, 3.0f}._1y(), f32x2{1.0f, 3.0f}));
626static_assert(equal(f32x2{2.0f, 3.0f}._10(), f32x2{1.0f, 0.0f}));
627static_assert(equal(f32x2{2.0f, 3.0f}._11(), f32x2{1.0f, 1.0f}));
628
629
630} // namespace v1
631}
632
633
634template<class T, size_t N>
635struct std::tuple_size<::hi::simd<T, N>> : std::integral_constant<size_t, N> {};
636
637template<size_t I, class T, size_t N>
638struct std::tuple_element<I, ::hi::simd<T, N>> {
639 using type = T;
640};
641
642template<typename T, size_t N>
643struct std::equal_to<::hi::simd<T, N>> {
644 constexpr bool operator()(::hi::simd<T, N> const& lhs, ::hi::simd<T, N> const& rhs) const noexcept
645 {
646 return equal(lhs, rhs);
647 }
648};
649
650hi_export template<typename T, size_t N>
651struct std::formatter<::hi::simd<T, N>, char> : std::formatter<std::string, char> {
652 auto format(::hi::simd<T, N> const& t, auto& fc) const
653 {
654 auto str = std::string{"("};
655
656 for (auto i = 0; i != N; ++i) {
657 if (i != 0) {
658 str += ", ";
659 }
660 str += std::format("{}", t[i]);
661 }
662 str += ')';
663
664 return std::formatter<std::string, char>::format(str, fc);
665 }
666};
667
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
The HikoGUI namespace.
Definition recursive_iterator.hpp:15
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:378
Intrinsic operations on arrays.
Definition array_generic.hpp:27
hi_force_inline static constexpr size_t get_mask(array_type a) noexcept
Get an integer mask where each bit in the mask corresponds with the top-bit of each element.
Definition array_generic.hpp:208
hi_force_inline static constexpr array_type andnot(array_type a, array_type b) noexcept
andnot of two operands
Definition array_generic.hpp:673
hi_force_inline static constexpr array_type set_mask(size_t mask) noexcept
Set each element to all ones or all zero based on the bits of the mask.
Definition array_generic.hpp:189
hi_force_inline static constexpr bool test(array_type a, array_type b) noexcept
Test the two operands.
Definition array_generic.hpp:556
hi_force_inline static constexpr bool all_equal(array_type a, array_type b) noexcept
Compare the two operands.
Definition array_generic.hpp:575
hi_force_inline static constexpr array_type hadd(array_type a, array_type b) noexcept
Add the elements of both operands pairwise and return the packed result.
Definition array_generic.hpp:744
Definition simd_intf.hpp:18
T equal(T... args)