7#include "native_f32x4_sse.hpp"
8#include "native_f64x4_avx.hpp"
9#include "native_i32x4_sse2.hpp"
10#include "native_i64x4_avx2.hpp"
11#include "native_u32x4_sse2.hpp"
12#include "native_simd_conversions_x86.hpp"
14#include "../utility/module.hpp"
27hi_warning_ignore_msvc(4702);
30hi_warning_ignore_msvc(26467);
33hi_warning_ignore_msvc(26472)
35#define HI_X_runtime_evaluate_if_valid(...) \
37 if (not std::is_constant_evaluated()) { \
38 if constexpr (requires { __VA_ARGS__; }) { \
44#define HI_X_accessor(index, name) \
45 [[nodiscard]] constexpr T name() const noexcept \
48 HI_X_runtime_evaluate_if_valid(get<index>(reg())); \
49 return std::get<index>(v); \
52 [[nodiscard]] constexpr T& name() noexcept \
55 return std::get<index>(v); \
58#define HI_X_binary_math_op(op) \
59 [[nodiscard]] friend constexpr simd operator op(simd lhs, simd rhs) noexcept \
60 requires(requires(value_type a, value_type b) { a op b; }) \
62 HI_X_runtime_evaluate_if_valid(simd{lhs.reg() op rhs.reg()}); \
65 for (std::size_t i = 0; i != N; ++i) { \
66 r[i] = lhs[i] op rhs[i]; \
71#define HI_X_binary_bit_op(op) \
72 [[nodiscard]] friend constexpr simd operator op(simd lhs, simd rhs) noexcept \
74 HI_X_runtime_evaluate_if_valid(simd{lhs.reg() op rhs.reg()}); \
77 for (std::size_t i = 0; i != N; ++i) { \
78 hilet lhs_vi = std::bit_cast<unsigned_type>(lhs[i]); \
79 hilet rhs_vi = std::bit_cast<unsigned_type>(rhs[i]); \
80 hilet r_vi = static_cast<unsigned_type>(lhs_vi op rhs_vi); \
81 r[i] = std::bit_cast<value_type>(r_vi); \
86#define HI_X_binary_shift_op(op) \
87 [[nodiscard]] friend constexpr simd operator op(simd const& lhs, unsigned int rhs) noexcept \
89 HI_X_runtime_evaluate_if_valid(simd{lhs.reg() op rhs}); \
92 for (std::size_t i = 0; i != N; ++i) { \
93 r.v[i] = lhs.v[i] op rhs; \
98#define HI_X_binary_cmp_op(op) \
99 [[nodiscard]] friend constexpr simd operator op(simd lhs, simd rhs) noexcept \
100 requires(requires(value_type a, value_type b) { a op b; }) \
102 HI_X_runtime_evaluate_if_valid(simd{lhs.reg() op rhs.reg()}); \
105 for (std::size_t i = 0; i != N; ++i) { \
106 r[i] = lhs[i] op rhs[i] ? ones_value : zero_value; \
111#define HI_X_binary_op_broadcast(op) \
112 [[nodiscard]] friend constexpr auto operator op(value_type lhs, simd rhs) noexcept \
113 requires(requires(value_type a, value_type b) { a op b; }) \
115 return broadcast(lhs) op rhs; \
118 [[nodiscard]] friend constexpr auto operator op(simd lhs, value_type rhs) noexcept \
119 requires(requires(value_type a, value_type b) { a op b; }) \
121 return lhs op broadcast(rhs); \
124#define HI_X_inplace_op(long_op, short_op) \
125 constexpr simd& operator long_op(auto rhs) noexcept \
126 requires(requires { *this short_op rhs; }) \
128 return *this = *this short_op rhs; \
131namespace hi::inline
v1 {
133template<numeric_limited T, std::
size_t N>
135 using value_type = T;
136 constexpr static size_t size = N;
138 using unsigned_type = make_uintxx_t<
sizeof(value_type) * CHAR_BIT>;
140 constexpr static bool has_native_type =
requires {
typename native_simd<value_type, size>::value_type; };
141 using native_type = native_simd<value_type, size>;
144 using size_type =
typename array_type::size_type;
145 using difference_type =
typename array_type::difference_type;
146 using reference =
typename array_type::reference;
147 using const_reference =
typename array_type::const_reference;
148 using pointer =
typename array_type::pointer;
149 using const_pointer =
typename array_type::const_pointer;
150 using iterator =
typename array_type::iterator;
151 using const_iterator =
typename array_type::const_iterator;
153 constexpr static value_type zero_value = value_type{};
158 constexpr simd() noexcept
160 if (not std::is_constant_evaluated()) {
161 if constexpr (
requires { *
this = simd{native_type{}}; }) {
162 *
this = simd{native_type{}};
168 constexpr simd(simd
const& rhs)
noexcept =
default;
169 constexpr simd(simd&& rhs)
noexcept =
default;
170 constexpr simd& operator=(simd
const& rhs)
noexcept =
default;
171 constexpr simd& operator=(simd&& rhs)
noexcept =
default;
173 template<numeric_limited U>
174 [[nodiscard]]
constexpr explicit simd(simd<U, N>
const& other)
noexcept
176 if (not std::is_constant_evaluated()) {
177 if constexpr (
requires { *
this = simd{native_type{
other.reg()}}; }) {
178 *
this = simd{native_type{
other.reg()}};
184 if constexpr (std::is_integral_v<T> and std::is_floating_point_v<U>) {
186 v[i] =
static_cast<value_type
>(
std::round(other[i]));
188 v[i] =
static_cast<value_type
>(
other[i]);
193 template<numeric_limited U>
194 [[nodiscard]]
constexpr explicit simd(simd<U, size / 2>
const& a, simd<U, size / 2>
const& b)
noexcept
196 if (not std::is_constant_evaluated()) {
197 if constexpr (
requires { simd{native_type{a.reg(), b.reg()}}; }) {
198 *
this = simd{native_type{a.reg(), b.reg()}};
204 hilet tmp = i < (size / 2) ? a[i] : b[i];
205 if constexpr (std::is_integral_v<T> and std::is_floating_point_v<U>) {
207 v[i] =
static_cast<value_type
>(
std::round(tmp));
209 v[i] =
static_cast<value_type
>(tmp);
214 template<std::convertible_to<value_type>... Args>
215 [[nodiscard]]
constexpr explicit simd(value_type first, Args... args)
noexcept
217 if (not std::is_constant_evaluated()) {
218 if constexpr (
requires { simd{native_type{first,
static_cast<value_type
>(args)...}}; }) {
219 *
this = simd{native_type{first,
static_cast<value_type
>(args)...}};
224 v = array_type{first,
static_cast<value_type
>(args)...};
227 [[nodiscard]]
static constexpr simd broadcast(T rhs)
noexcept
229 HI_X_runtime_evaluate_if_valid(simd{native_type::broadcast(rhs)});
238 [[nodiscard]]
static constexpr simd epsilon() noexcept
240 if constexpr (std::is_floating_point_v<T>) {
243 return broadcast(T{0});
260 [[nodiscard]]
explicit simd(native_type rhs)
noexcept
261 requires(
requires {
typename native_type::value_type; })
262 : v(static_cast<array_type>(rhs))
266 [[nodiscard]]
auto reg() const noexcept
267 requires(requires {
typename native_type::value_type; })
269 return native_type{v};
272 template<numeric_limited O,
size_t M>
273 [[nodiscard]]
constexpr static simd cast_from(simd<O, M>
const& rhs)
noexcept
274 requires(
sizeof(simd<O, M>) ==
sizeof(simd))
276 HI_X_runtime_evaluate_if_valid(simd{native_type::cast_from(rhs.reg())});
278 return std::bit_cast<simd>(rhs);
285 template<std::
size_t S>
286 [[nodiscard]]
static constexpr simd
load(std::byte
const *ptr)
noexcept
288 HI_X_runtime_evaluate_if_valid(simd{native_type{ptr}});
299 [[nodiscard]]
static constexpr simd
load(std::byte
const *ptr)
noexcept
301 HI_X_runtime_evaluate_if_valid(simd{native_type{ptr}});
312 [[nodiscard]]
static constexpr simd
load(T
const *ptr)
noexcept
314 HI_X_runtime_evaluate_if_valid(simd{native_type{ptr}});
321 template<std::
size_t S>
322 constexpr void store(std::byte *ptr)
const noexcept
324 HI_X_runtime_evaluate_if_valid(reg().store(ptr));
331 constexpr void store(std::byte *ptr)
const noexcept
333 HI_X_runtime_evaluate_if_valid(reg().store(ptr));
334 store<sizeof(*this)>(ptr);
337 [[nodiscard]]
constexpr size_t mask() const noexcept
339 HI_X_runtime_evaluate_if_valid(reg().mask());
342 for (
auto i = N; i != 0; --i) {
344 r |= std::bit_cast<unsigned_type>(v[i - 1]) >> (
sizeof(unsigned_type) * CHAR_BIT - 1);
349 [[nodiscard]]
constexpr T
const& operator[](
std::size_t i)
const noexcept
351 static_assert(std::endian::native == std::endian::little,
"Indices need to be reversed on big endian machines");
356 [[nodiscard]]
constexpr T& operator[](
std::size_t i)
noexcept
358 static_assert(std::endian::native == std::endian::little,
"Indices need to be reversed on big endian machines");
363 [[nodiscard]]
constexpr reference front() noexcept
368 [[nodiscard]]
constexpr const_reference front() const noexcept
373 [[nodiscard]]
constexpr reference back() noexcept
378 [[nodiscard]]
constexpr const_reference back() const noexcept
383 [[nodiscard]]
constexpr pointer data() noexcept
388 [[nodiscard]]
constexpr const_pointer data() const noexcept
393 [[nodiscard]]
constexpr iterator
begin() noexcept
398 [[nodiscard]]
constexpr const_iterator
begin() const noexcept
403 [[nodiscard]]
constexpr const_iterator cbegin() const noexcept
408 [[nodiscard]]
constexpr iterator
end() noexcept
413 [[nodiscard]]
constexpr const_iterator
end() const noexcept
418 [[nodiscard]]
constexpr const_iterator cend() const noexcept
423 [[nodiscard]]
constexpr bool empty() const noexcept
436 HI_X_accessor(0, width);
437 HI_X_accessor(1, height);
438 HI_X_accessor(2, depth);
440 HI_X_binary_math_op(+);
441 HI_X_binary_math_op(-);
442 HI_X_binary_math_op(*);
443 HI_X_binary_math_op(/);
444 HI_X_binary_math_op(%);
446 HI_X_binary_cmp_op(==);
447 HI_X_binary_cmp_op(!=);
448 HI_X_binary_cmp_op(<);
449 HI_X_binary_cmp_op(>);
450 HI_X_binary_cmp_op(<=);
451 HI_X_binary_cmp_op(>=);
453 HI_X_binary_bit_op(^);
454 HI_X_binary_bit_op(&);
455 HI_X_binary_bit_op(|);
456 HI_X_binary_shift_op(<<);
457 HI_X_binary_shift_op(>>);
459 [[nodiscard]]
friend constexpr bool equal(simd lhs, simd rhs)
noexcept
461 HI_X_runtime_evaluate_if_valid(
equal(lhs.reg(), rhs.reg()));
463 for (
auto i = 0_uz; i != N; ++i) {
464 if (lhs.v[i] != rhs.v[i]) {
471 HI_X_binary_op_broadcast(==);
472 HI_X_binary_op_broadcast(!=);
473 HI_X_binary_op_broadcast(<);
474 HI_X_binary_op_broadcast(>);
475 HI_X_binary_op_broadcast(<=);
476 HI_X_binary_op_broadcast(>=);
477 HI_X_binary_op_broadcast(+);
478 HI_X_binary_op_broadcast(-);
479 HI_X_binary_op_broadcast(*);
480 HI_X_binary_op_broadcast(/);
481 HI_X_binary_op_broadcast(%);
482 HI_X_binary_op_broadcast(&);
483 HI_X_binary_op_broadcast(|);
484 HI_X_binary_op_broadcast(^);
486 HI_X_inplace_op(+=, +);
487 HI_X_inplace_op(-=, -);
488 HI_X_inplace_op(*=, *);
489 HI_X_inplace_op(/=, /);
490 HI_X_inplace_op(%=, %);
491 HI_X_inplace_op(|=, |);
492 HI_X_inplace_op(&=, &);
493 HI_X_inplace_op(^=, ^);
494 HI_X_inplace_op(<<=, <<);
495 HI_X_inplace_op(>>=, >>);
501 template<std::
size_t I>
502 [[nodiscard]]
friend constexpr T& get(simd& rhs)
noexcept
504 static_assert(I < N,
"Index out of bounds");
505 return std::get<I>(rhs.v);
512 template<std::
size_t I>
513 [[nodiscard]]
friend constexpr T get(simd
const& rhs)
noexcept
515 static_assert(I < N,
"Index out of bounds");
516 HI_X_runtime_evaluate_if_valid(get<I>(rhs.reg()));
517 return std::get<I>(rhs.v);
527 template<std::
size_t I>
528 [[nodiscard]]
constexpr friend simd insert(simd
const& lhs, value_type rhs)
noexcept
530 static_assert(I < size);
531 HI_X_runtime_evaluate_if_valid(simd{insert<I>(lhs.reg(), rhs)});
534 std::get<I>(r.v) = rhs;
543 [[nodiscard]]
friend constexpr simd set_zero(simd rhs)
noexcept
545 HI_X_runtime_evaluate_if_valid(simd{set_zero<Mask>(rhs.reg())});
549 if (to_bool((Mask >> i) & 1)) {
565 template<std::
size_t Mask>
566 [[nodiscard]]
friend constexpr simd blend(simd
const& lhs, simd
const& rhs)
noexcept
568 HI_X_runtime_evaluate_if_valid(simd{blend<Mask>(lhs.reg(), rhs.reg())});
572 r[i] = to_bool((Mask >> i) & 1) ? rhs[i] : lhs[i];
579 [[nodiscard]]
friend constexpr simd blend(simd
const& a, simd
const& b, simd
const& mask)
581 HI_X_runtime_evaluate_if_valid(simd{blend(a.reg(), b.reg(), mask.reg())});
585 r[i] = mask[i] != T{0} ? b[i] : a[i];
594 template<std::
size_t Mask>
595 [[nodiscard]]
friend constexpr simd neg(simd rhs)
noexcept
597 return blend<Mask>(rhs, -rhs);
600 [[nodiscard]]
friend constexpr simd operator-(simd
const& rhs)
noexcept
602 HI_X_runtime_evaluate_if_valid(simd{-rhs.reg()});
606 [[nodiscard]]
friend constexpr simd abs(simd
const& rhs)
noexcept
608 HI_X_runtime_evaluate_if_valid(simd{abs(rhs.reg())});
609 return max(rhs, -rhs);
612 [[nodiscard]]
friend constexpr simd rcp(simd
const& rhs)
noexcept
614 HI_X_runtime_evaluate_if_valid(simd{rcp(rhs.reg())});
618 [[nodiscard]]
friend constexpr simd
sqrt(simd
const& rhs)
noexcept
620 HI_X_runtime_evaluate_if_valid(simd{
sqrt(rhs.reg())});
629 [[nodiscard]]
friend constexpr simd rcp_sqrt(simd
const& rhs)
noexcept
631 HI_X_runtime_evaluate_if_valid(simd{rcp_sqrt(rhs.reg())});
632 return rcp(
sqrt(rhs));
635 [[nodiscard]]
friend constexpr simd
floor(simd
const& rhs)
noexcept
636 requires(std::is_floating_point_v<value_type>)
638 HI_X_runtime_evaluate_if_valid(simd{
floor(rhs.reg())});
647 [[nodiscard]]
friend constexpr simd
ceil(simd
const& rhs)
noexcept
648 requires(std::is_floating_point_v<value_type>)
650 HI_X_runtime_evaluate_if_valid(simd{
ceil(rhs.reg())});
659 [[nodiscard]]
friend constexpr simd
round(simd
const& rhs)
noexcept
660 requires(std::is_floating_point_v<value_type>)
662 HI_X_runtime_evaluate_if_valid(simd{
round(rhs.reg())});
678 template<std::
size_t Mask>
679 [[nodiscard]] hi_force_inline
friend constexpr T dot(simd
const& lhs, simd
const& rhs)
noexcept
681 HI_X_runtime_evaluate_if_valid(get<0>(dot<Mask>(lhs.reg(), rhs.reg())));
685 if (to_bool(Mask & (1_uz << i))) {
686 r += lhs.v[i] * rhs.v[i];
698 template<std::
size_t Mask>
699 [[nodiscard]]
friend T
hypot(simd
const& rhs)
noexcept
700 requires(std::is_floating_point_v<value_type>)
702 HI_X_runtime_evaluate_if_valid(get<0>(
sqrt(dot<Mask>(rhs.reg(), rhs.reg()))));
712 template<std::
size_t Mask>
713 [[nodiscard]] hi_force_inline
friend constexpr T squared_hypot(simd
const& rhs)
noexcept
715 HI_X_runtime_evaluate_if_valid(get<0>(dot<Mask>(rhs.reg(), rhs.reg())));
716 return dot<Mask>(rhs, rhs);
724 template<std::
size_t Mask>
725 [[nodiscard]]
friend constexpr T rcp_hypot(simd
const& rhs)
noexcept
727 HI_X_runtime_evaluate_if_valid(get<0>(rcp_sqrt(dot<Mask>(rhs.reg(), rhs.reg()))));
728 return 1.0f / hypot<Mask>(rhs);
738 template<std::
size_t Mask>
739 [[nodiscard]]
friend constexpr simd normalize(simd
const& rhs)
noexcept
741 HI_X_runtime_evaluate_if_valid(simd{rhs * rcp_sqrt(dot<Mask>(rhs.reg(), rhs.reg()))});
743 hilet rcp_hypot_ = rcp_hypot<Mask>(rhs);
747 if (to_bool(Mask & (1_uz << i))) {
748 r.v[i] = rhs.v[i] * rcp_hypot_;
758 [[nodiscard]]
friend constexpr simd rotl(simd
const& lhs,
unsigned int rhs)
noexcept
760 hi_axiom(rhs > 0 and rhs <
sizeof(value_type) * CHAR_BIT);
762 hilet remainder = narrow_cast<unsigned int>(
sizeof(value_type) * CHAR_BIT - rhs);
764 return (lhs << rhs) | (lhs >>
remainder);
771 [[nodiscard]]
friend constexpr simd rotr(simd
const& lhs,
unsigned int rhs)
noexcept
773 hi_axiom(rhs > 0 and rhs <
sizeof(value_type) * CHAR_BIT);
775 hilet remainder = narrow_cast<unsigned int>(
sizeof(value_type) * CHAR_BIT - rhs);
777 return (lhs >> rhs) | (lhs <<
remainder);
780 [[nodiscard]]
friend constexpr simd
min(simd
const& lhs, simd
const& rhs)
noexcept
782 HI_X_runtime_evaluate_if_valid(simd{
min(lhs.reg(), rhs.reg())});
786 r.v[i] =
std::min(lhs.v[i], rhs.v[i]);
791 [[nodiscard]]
friend constexpr simd
max(simd
const& lhs, simd
const& rhs)
noexcept
793 HI_X_runtime_evaluate_if_valid(simd{
max(lhs.reg(), rhs.reg())});
797 r.v[i] =
std::max(lhs.v[i], rhs.v[i]);
802 [[nodiscard]]
friend constexpr simd clamp(simd
const& lhs, simd
const& low, simd
const& high)
noexcept
804 return min(
max(lhs, low), high);
807 [[nodiscard]]
friend constexpr simd hadd(simd
const& lhs, simd
const& rhs)
noexcept
809 HI_X_runtime_evaluate_if_valid(simd{horizontal_add(lhs.reg(), rhs.reg())});
818 auto tmp = lhs[src_i++];
825 auto tmp = rhs[src_i++];
832 [[nodiscard]]
friend constexpr simd hsub(simd
const& lhs, simd
const& rhs)
noexcept
834 HI_X_runtime_evaluate_if_valid(simd{horizontal_sub(lhs.reg(), rhs.reg())});
843 auto tmp = lhs[src_i++];
850 auto tmp = rhs[src_i++];
861 template<std::
size_t Mask>
862 [[nodiscard]]
friend constexpr simd addsub(simd
const& lhs, simd
const& rhs)
noexcept
865 return lhs + neg<Mask ^ not_mask>(rhs);
870 [[nodiscard]]
friend constexpr simd cross_2D(simd
const& rhs)
noexcept
873 return simd{-rhs.y(), rhs.x()};
878 [[nodiscard]]
friend constexpr simd normal_2D(simd
const& rhs)
noexcept
881 return normalize<0b0011>(cross_2D(rhs));
887 [[nodiscard]]
friend constexpr float cross_2D(simd
const& lhs, simd
const& rhs)
noexcept
890 hilet tmp1 = rhs.yxwz();
891 hilet tmp2 = lhs * tmp1;
892 hilet tmp3 = hsub(tmp2, tmp2);
900 [[nodiscard]]
constexpr friend simd cross_3D(simd
const& lhs, simd
const& rhs)
noexcept
903 hilet a_left = lhs.yzxw();
904 hilet b_left = rhs.zxyw();
907 hilet a_right = lhs.zxyw();
908 hilet b_right = rhs.yzxw();
913 [[nodiscard]]
static constexpr simd byte_srl_shuffle_indices(
unsigned int rhs)
914 requires(std::is_same_v<value_type, int8_t> and size == 16)
916 static_assert(std::endian::native == std::endian::little);
919 for (
auto i = 0; i != 16; ++i) {
920 if ((i + rhs) < 16) {
921 r[i] = narrow_cast<int8_t>(i + rhs);
930 [[nodiscard]]
static constexpr simd byte_sll_shuffle_indices(
unsigned int rhs)
931 requires(std::is_same_v<value_type, int8_t> and size == 16)
933 static_assert(std::endian::native == std::endian::little);
936 for (
auto i = 0; i != 16; ++i) {
937 if ((i - rhs) >= 0) {
938 r[i] = narrow_cast<int8_t>(i - rhs);
949 [[nodiscard]]
friend constexpr simd permute(simd
const& lhs, simd
const& rhs)
noexcept
950 requires(std::is_integral_v<value_type>)
952 HI_X_runtime_evaluate_if_valid(simd{permute(lhs.reg(), rhs.reg())});
957 r[i] = lhs[rhs[i] & 0xf];
968 [[nodiscard]]
friend constexpr simd midpoint(simd
const& p1, simd
const& p2)
noexcept
970 return (p1 + p2) * 0.5f;
975 [[nodiscard]]
friend constexpr simd reflect_point(simd
const& p, simd
const anchor)
noexcept
977 return anchor - (p - anchor);
983 hi_warning_ignore_msvc(26494);
984 template<
typename... Columns>
987 static_assert(
sizeof...(Columns) == size,
"Can only transpose square matrices");
989 if (not std::is_constant_evaluated()) {
990 if constexpr (
requires { transpose(columns.reg()...); }) {
991 hilet tmp = transpose(columns.reg()...);
993 for (
auto i = 0_uz; i != size; ++i) {
1001 auto f = [&r, &columns... ]<
std::size_t... Ints>(std::index_sequence<Ints...>)
1003 auto tf = [&r](
auto i,
auto v) {
1009 static_cast<void>((tf(Ints, columns) + ...));
1011 f(std::make_index_sequence<
sizeof...(columns)>{});
1016 [[nodiscard]]
constexpr friend simd
composit(simd
const& under, simd
const& over)
noexcept
1017 requires(N == 4 && std::is_floating_point_v<T>)
1019 if (get<3>(over) <= value_type{0}) {
1023 if (get<3>(over) >= value_type{1}) {
1028 hilet over_alpha = over.wwww();
1029 hilet under_alpha = under.wwww();
1031 hilet over_color = over.xyz1();
1032 hilet under_color = under.xyz1();
1034 hilet output_color = over_color * over_alpha + under_color * under_alpha * (T{1} - over_alpha);
1036 return output_color / output_color.www1();
1039 [[nodiscard]]
constexpr friend simd
composit(simd
const& under, simd
const& over)
noexcept
1040 requires(std::is_same_v<value_type, float16> and size == 4)
1042 return simd{
composit(
static_cast<simd<float, 4>
>(under),
static_cast<simd<float, 4>
>(over))};
1054 r += std::format(
"{}", rhs[i]);
1069 template<std::
size_t FromElement, std::
size_t ToElement>
1070 [[nodiscard]]
constexpr friend simd insert(simd
const& lhs, simd
const& rhs)
1072 HI_X_runtime_evaluate_if_valid(simd{insert<FromElement, ToElement>(lhs.reg(), rhs.reg())});
1076 r[i] = (i == ToElement) ? rhs[FromElement] : lhs[i];
1089 template<fixed_
string Order>
1090 [[nodiscard]]
constexpr simd swizzle()
const
1092 static_assert(Order.size() <= N);
1094 HI_X_runtime_evaluate_if_valid(simd{reg().swizzle<Order>()});
1097 swizzle_detail<0, Order>(r);
1101#define SWIZZLE(name, str) \
1102 [[nodiscard]] constexpr simd name() const noexcept \
1103 requires(sizeof(str) - 1 <= N) \
1105 return swizzle<str>(); \
1108#define SWIZZLE_4D(name, str) \
1109 SWIZZLE(name##0, str "0") \
1110 SWIZZLE(name##1, str "1") \
1111 SWIZZLE(name##x, str "a") \
1112 SWIZZLE(name##y, str "b") \
1113 SWIZZLE(name##z, str "c") \
1114 SWIZZLE(name##w, str "d")
1116#define SWIZZLE_3D(name, str) \
1117 SWIZZLE_4D(name##0, str "0") \
1118 SWIZZLE_4D(name##1, str "1") \
1119 SWIZZLE_4D(name##x, str "a") \
1120 SWIZZLE_4D(name##y, str "b") \
1121 SWIZZLE_4D(name##z, str "c") \
1122 SWIZZLE_4D(name##w, str "d") \
1123 SWIZZLE(name##0, str "0") \
1124 SWIZZLE(name##1, str "1") \
1125 SWIZZLE(name##x, str "a") \
1126 SWIZZLE(name##y, str "b") \
1127 SWIZZLE(name##z, str "c") \
1128 SWIZZLE(name##w, str "d")
1130#define SWIZZLE_2D(name, str) \
1131 SWIZZLE_3D(name##0, str "0") \
1132 SWIZZLE_3D(name##1, str "1") \
1133 SWIZZLE_3D(name##x, str "a") \
1134 SWIZZLE_3D(name##y, str "b") \
1135 SWIZZLE_3D(name##z, str "c") \
1136 SWIZZLE_3D(name##w, str "d") \
1137 SWIZZLE(name##0, str "0") \
1138 SWIZZLE(name##1, str "1") \
1139 SWIZZLE(name##x, str "a") \
1140 SWIZZLE(name##y, str "b") \
1141 SWIZZLE(name##z, str "c") \
1142 SWIZZLE(name##w, str "d")
1156 template<
size_t I, fixed_
string Order>
1157 constexpr void swizzle_detail(simd& r)
const noexcept
1159 static_assert(I < size);
1162 constexpr char c = I < Order.size() ? get<I>(Order) :
'0';
1164 if constexpr (c ==
'1') {
1165 r = insert<I>(r, value_type{1});
1167 }
else if constexpr (c ==
'0') {
1168 r = insert<I>(r, value_type{0});
1170 }
else if constexpr (c >=
'a' and c <=
'v') {
1171 constexpr size_t src_index = c -
'a';
1172 static_assert(src_index < size);
1174 r = insert<I>(r, get<src_index>(*
this));
1176 }
else if constexpr (c >=
'w' and c <=
'z') {
1177 constexpr size_t src_index = c ==
'x' ? 0 : c ==
'y' ? 1 : c ==
'z' ? 2 : 3;
1178 static_assert(src_index < size);
1180 r = insert<I>(r, get<src_index>(*
this));
1186 if constexpr (I + 1 < size) {
1187 swizzle_detail<I + 1, Order>(r);
1192using i8x1 = simd<int8_t, 1>;
1193using i8x2 = simd<int8_t, 2>;
1194using i8x4 = simd<int8_t, 4>;
1195using i8x8 = simd<int8_t, 8>;
1196using i8x16 = simd<int8_t, 16>;
1197using i8x32 = simd<int8_t, 32>;
1198using i8x64 = simd<int8_t, 64>;
1200using u8x1 = simd<uint8_t, 1>;
1201using u8x2 = simd<uint8_t, 2>;
1202using u8x4 = simd<uint8_t, 4>;
1203using u8x8 = simd<uint8_t, 8>;
1204using u8x16 = simd<uint8_t, 16>;
1205using u8x32 = simd<uint8_t, 32>;
1206using u8x64 = simd<uint8_t, 64>;
1208using i16x1 = simd<int16_t, 1>;
1209using i16x2 = simd<int16_t, 2>;
1210using i16x4 = simd<int16_t, 4>;
1211using i16x8 = simd<int16_t, 8>;
1212using i16x16 = simd<int16_t, 16>;
1213using i16x32 = simd<int16_t, 32>;
1215using u16x1 = simd<uint16_t, 1>;
1216using u16x2 = simd<uint16_t, 2>;
1217using u16x4 = simd<uint16_t, 4>;
1218using u16x8 = simd<uint16_t, 8>;
1219using u16x16 = simd<uint16_t, 16>;
1220using u16x32 = simd<uint16_t, 32>;
1222using f16x4 = simd<float16, 4>;
1224using i32x1 = simd<int32_t, 1>;
1225using i32x2 = simd<int32_t, 2>;
1226using i32x4 = simd<int32_t, 4>;
1227using i32x8 = simd<int32_t, 8>;
1228using i32x16 = simd<int32_t, 16>;
1230using u32x1 = simd<uint32_t, 1>;
1231using u32x2 = simd<uint32_t, 2>;
1232using u32x4 = simd<uint32_t, 4>;
1233using u32x8 = simd<uint32_t, 8>;
1234using u32x16 = simd<uint32_t, 16>;
1236using f32x1 = simd<float, 1>;
1237using f32x2 = simd<float, 2>;
1238using f32x4 = simd<float, 4>;
1239using f32x8 = simd<float, 8>;
1240using f32x16 = simd<float, 16>;
1242using i64x1 = simd<int64_t, 1>;
1243using i64x2 = simd<int64_t, 2>;
1244using i64x4 = simd<int64_t, 4>;
1245using i64x8 = simd<int64_t, 8>;
1247using u64x1 = simd<uint64_t, 1>;
1248using u64x2 = simd<uint64_t, 2>;
1249using u64x4 = simd<uint64_t, 4>;
1250using u64x8 = simd<uint64_t, 8>;
1252using f64x1 = simd<double, 1>;
1253using f64x2 = simd<double, 2>;
1254using f64x4 = simd<double, 4>;
1255using f64x8 = simd<double, 8>;
1259template<
class T, std::
size_t N>
1262template<std::
size_t I,
class T, std::
size_t N>
1263struct std::tuple_element<I,
hi::simd<T, N>> {
1267template<
typename T,
size_t N>
1269 constexpr bool operator()(::hi::simd<T, N>
const& lhs, ::hi::simd<T, N>
const& rhs)
const noexcept
1271 return equal(lhs, rhs);
1276template<
typename T,
size_t N>
1277inline bool operator==(::hi::simd<T, N> lhs, ::hi::simd<T, N> rhs)
noexcept
1283template<
typename T,
size_t N>
1284inline bool operator!=(::hi::simd<T, N> lhs, ::hi::simd<T, N> rhs)
noexcept
1290#undef HI_X_binary_cmp_op
1291#undef HI_X_binary_math_op
1292#undef HI_X_binary_bit_op
1293#undef HI_X_binary_shift_op
1294#undef HI_X_binary_op_broadcast
1295#undef HI_X_inplace_op
1296#undef HI_X_runtime_evaluate_if_valid
#define hi_static_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:323
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
@ other
The gui_event does not have associated data.
DOXYGEN BUG.
Definition algorithm.hpp:13
void composit(pixmap_span< sfloat_rgba16 > dst, hi::color color, graphic_path const &mask) noexcept
Composit color onto the destination image where the mask is solid.
constexpr T load(T const *src) noexcept
Load a numeric value from memory.
Definition endian.hpp:146
geometry/margins.hpp
Definition cache.hpp:11