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