Argon 0.1.0
Loading...
Searching...
No Matches
vector.hpp
1#pragma once
2#include <array>
3#include <bit>
4#include <cmath>
5#include <functional>
6#include <tuple>
7#include <type_traits>
8#include <utility>
9#include "arm_simd.hpp"
10#include "arm_simd/helpers.hpp"
11#include "arm_simd/helpers/multivector.hpp"
12#include "arm_simd/helpers/scalar.hpp"
13#include "arm_simd/helpers/vec64.hpp"
14#include "features.h"
15#include "helpers.hpp"
16#include "helpers/bool.hpp"
17#include "helpers/to_array.hpp"
18#include "lane.hpp"
19
20#ifdef __ARM_FEATURE_MVE
21#define simd mve
22#else
23#define simd neon
24#endif
25
26#ifdef ARGON_PLATFORM_SIMDE
27#define ace [[gnu::always_inline]] inline
28#elifdef __clang__
29#define ace [[gnu::always_inline]] constexpr
30#else
31#define ace [[gnu::always_inline]] inline
32#endif
33
34namespace argon {
35template <typename T>
36concept arithmetic = std::is_arithmetic_v<T>;
37
42template <typename T, typename... Ts>
43inline constexpr bool is_one_of = std::disjunction_v<std::is_same<T, Ts>...>;
44
49template <typename VectorType>
50class Vector {
51 public:
52 template <size_t LaneIndex>
55 using scalar_type = simd::Scalar_t<VectorType>;
56 using vector_type = VectorType;
58 using predicate_type = Bool_t<VectorType>;
60
62 static constexpr size_t lanes = (simd::is_quadword_v<VectorType> ? 16 : 8) / sizeof(scalar_type);
63
65 constexpr Vector() = default;
66
67 constexpr Vector(Vector&& other) = default;
68 constexpr Vector(const Vector& other) = default;
69 constexpr Vector& operator=(Vector&& other) = default;
70 constexpr Vector& operator=(const Vector& other) = default;
71
74 ace Vector(VectorType vector) : vec_{std::move(vector)} {};
75
79 ace Vector(scalar_type scalar) : vec_(FromScalar(scalar)) {};
80
81#ifndef ARGON_PLATFORM_MVE
85 ace Vector(argon::Lane<VectorType> lane) : vec_(FromLane(lane)) {};
86
91 template <size_t LaneIndex>
93#endif
94
95 template <typename... ArgTypes>
96 requires(sizeof...(ArgTypes) > 1)
97 ace Vector(ArgTypes... args) : vec_{std::forward<ArgTypes>(args)...} {}
98
104 ace static argon_type LoadScalar(const scalar_type* ptr) { return LoadCopy(ptr); }
105
110 ace static argon_type FromScalar(scalar_type scalar) {
111#ifdef ARGON_PLATFORM_MVE
112 return simd::duplicate(scalar);
113#else
114 return simd::duplicate<VectorType>(scalar);
115#endif
116 }
117
122 template <simd::is_vector_type IntrinsicType>
124#ifdef ARGON_PLATFORM_MVE
125 return simd::duplicate(lane.Get());
126#else
127 return simd::duplicate_lane<vector_type>(lane.vec(), lane.lane());
128#endif
129 }
130
135 template <size_t LaneIndex>
137#ifdef ARGON_PLATFORM_MVE
138 return simd::duplicate(lane.Get());
139#else
140 if constexpr (simd::is_quadword_v<VectorType>) {
141#if __ARM_ARCH >= 8
142 return simd::duplicate_lane_quad<LaneIndex>(lane.vec());
143#else
144 // On A32, vec() returns the 64-bit half-register (low or high).
145 // The template arg must be the lane index within that half-vector.
146 constexpr size_t local_lane = LaneIndex >= (lanes / 2) ? LaneIndex - (lanes / 2) : LaneIndex;
147 return simd::duplicate_lane_quad<local_lane>(lane.vec());
148#endif
149 } else {
150 return simd::duplicate_lane<LaneIndex>(lane.vec());
151 }
152#endif
153 }
154
161 ace static argon_type Iota(scalar_type start) {
162 // TODO: Remove this once MSVC 19.44 is released.
163#if __cpp_if_consteval >= 202106L
164 return IotaHelper(start, std::make_index_sequence<lanes>{});
165#else
166 return Argon{start}.Add(VectorType{0, 1, 2, 3});
167#endif
168 }
169
174 template <typename FuncType>
175 requires std::convertible_to<FuncType, std::function<scalar_type()>>
176 ace static argon_type Generate(FuncType body) {
177 // Build via a scalar array + Load rather than subscripting the raw vector:
178 // MSVC's SIMDe vector types are structs with no operator[].
179 std::array<scalar_type, lanes> out;
180 utility::constexpr_for<0, lanes, 1>([&]<size_t i>() { //
181 out[i] = body();
182 });
183 return Load(out.data());
184 }
185
191 template <typename FuncType>
192 requires std::convertible_to<FuncType, std::function<scalar_type(scalar_type)>>
193 ace static argon_type GenerateWithIndex(FuncType body) {
194 // Build via a scalar array + Load rather than subscripting the raw vector:
195 // MSVC's SIMDe vector types are structs with no operator[].
196 std::array<scalar_type, lanes> out;
197 utility::constexpr_for<0, lanes, 1>([&]<size_t i>() { //
198 out[i] = body(i);
199 });
200 return Load(out.data());
201 }
202
204 ace argon_type operator-() const { return Negate(); }
205
207 ace argon_type operator+(argon_type b) const { return Add(b); }
208
210 ace argon_type operator-(argon_type b) const { return Subtract(b); }
211
213 ace argon_type operator*(argon_type b) const { return Multiply(b); }
214
216 ace argon_type operator/(argon_type b) const { return Divide(b); }
217
219 ace argon_bool_type operator==(argon_type b) const { return Equal(b); }
220
222 ace argon_bool_type operator!=(argon_type b) const { return ~Equal(b); }
223
225 ace argon_bool_type operator<(argon_type b) const { return LessThan(b); }
226
229
232
235
237 ace argon_type operator++() const { return Add(1); }
238
240 ace argon_type operator--() const { return Subtract(1); }
241
243 ace argon_type operator&(argon_type b) const { return BitwiseAnd(b); }
244
246 ace argon_type operator|(argon_type b) const { return BitwiseOr(b); }
247
249 ace argon_type operator^(argon_type b) const { return BitwiseXor(b); }
250
252 ace argon_type operator~() const { return BitwiseNot(); }
253
255 ace Lane<const VectorType> operator[](const size_t i) const { return GetLane(i); }
256
258 ace lane_type operator[](const size_t i) { return GetLane(i); }
259
261 ace argon_type operator>>(const int i) const {
262#if ARGON_USE_COMPILER_EXTENSIONS
263 return vec_ >> i;
264#else
265 return ShiftRight(i);
266#endif
267 }
268
270 ace argon_type operator<<(const int i) const {
271#if ARGON_USE_COMPILER_EXTENSIONS
272 return vec_ << i;
273#else
274 return ShiftLeft(i);
275#endif
276 }
277
279 [[gnu::always_inline]] constexpr VectorType vec() const { return vec_; }
280
282 [[gnu::always_inline]] constexpr operator VectorType() const { return vec_; }
283
286 ace std::array<scalar_type, lanes> to_array() {
287 std::array<scalar_type, lanes> out;
288 simd::store1(out.data(), vec_);
289 return out;
290 }
291
296 ace const lane_type GetLane(const size_t i) const {
297#ifdef ARGON_PLATFORM_MVE
298 return vec_[i];
299#else
300 return {vec_, static_cast<int>(i)};
301#endif
302 }
303 ace lane_type GetLane(const size_t i) {
304#ifdef ARGON_PLATFORM_MVE
305 return vec_[i];
306#else
307 return {vec_, static_cast<int>(i)};
308#endif
309 }
310
314 ace const lane_type GetLane(const int i) const {
315#ifdef ARGON_PLATFORM_MVE
316 return vec_[i];
317#else
318 return {vec_, i};
319#endif
320 }
321
322 ace lane_type GetLane(const int i) {
323#ifdef ARGON_PLATFORM_MVE
324 return vec_[i];
325#else
326 return {vec_, i};
327#endif
328 }
329
333 template <size_t LaneIndex>
335#ifdef ARGON_PLATFORM_MVE
336 return vec_[LaneIndex];
337#else
338 return vec_;
339#endif
340 }
341
342 template <size_t LaneIndex>
344#ifdef ARGON_PLATFORM_MVE
345 return vec_[LaneIndex];
346#else
347 return vec_;
348#endif
349 }
350
352 ace const_lane_type<lanes - 1> LastLane() { return vec_; }
353
355 ace argon_type ShiftRight(const int i) const { return simd::shift_right(vec_, i); }
356
358 ace argon_type ShiftLeft(const int i) const { return simd::shift_left(vec_, i); }
359
361 ace argon_type Negate() const {
362 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
363 return -vec_;
364 } else {
365 return simd::negate(vec_);
366 }
367 }
368
370 ace argon_type Add(argon_type b) const {
371 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
372 return vec_ + b.vec_;
373 } else {
374 return simd::add(vec_, b);
375 }
376 }
377
380 ace argon_type AddHalve(argon_type b) const { return simd::add_halve(vec_, b); }
381
384 ace argon_type AddHalveRound(argon_type b) const { return simd::add_halve_round(vec_, b); }
385
389 ace argon_type AddSaturate(argon_type b) const { return simd::add_saturate(vec_, b); }
390
393 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
394 return vec_ - b.vec_;
395 } else {
396 return simd::subtract(vec_, b);
397 }
398 }
399
402 ace argon_type SubtractHalve(argon_type b) const { return simd::subtract_halve(vec_, b); }
403
405 ace argon_type SubtractSaturate(argon_type b) const { return simd::subtract_saturate(vec_, b); }
406
409 ace argon_type SubtractAbs(argon_type b) const { return simd::subtract_absolute(vec_, b); }
410
414#ifdef ARGON_PLATFORM_MVE
415 return mve::add(vec_, mve::subtract_absolute(b, c));
416#else
417 return neon::subtract_absolute_add(vec_, b, c);
418#endif
419 }
420
423 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
424 return vec_ * b.vec_;
425 } else {
426 return simd::multiply(vec_, b);
427 }
428 }
429
432 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
433 return vec_ * b;
434 } else {
435 return simd::multiply(vec_, b);
436 }
437 }
438
439#ifndef ARGON_PLATFORM_MVE
441 ace argon_type Multiply(lane_type b) const { return neon::multiply_lane(vec_, b.vec(), b.lane()); }
442
444 template <size_t LaneIndex>
446 return neon::multiply_lane(vec_, b.vec(), b.lane());
447 }
448#endif
449
453 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
454 return vec_ + b.vec_ * c.vec_;
455 } else {
456 return simd::multiply_add(vec_, b, c);
457 }
458 }
459
463 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
464 return vec_ + b.vec_ * c;
465 } else {
466 return simd::multiply_add(vec_, b, c);
467 }
468 }
469
472 ace argon_type MultiplyAdd(scalar_type b, argon_type c) const { return MultiplyAdd(c, b); }
473
474#ifndef ARGON_PLATFORM_MVE
478 return simd::multiply_add_lane(vec_, b.vec(), c.vec(), c.lane());
479 }
480
483 ace argon_type MultiplyAdd(lane_type b, argon_type c) const { return MultiplyAdd(c, b); }
484
487 template <size_t LaneIndex>
489 return simd::multiply_add_lane(vec_, b.vec(), c.vec(), c.lane());
490 }
491
493 template <size_t LaneIndex>
495 return MultiplyAdd(c, b);
496 }
497#endif
498
502#if ARGON_USE_COMPILER_EXTENSIONS
503 return vec_ - b.vec_ * c.vec_;
504#else
505 return simd::multiply_subtract(vec_, b, c);
506#endif
507 }
508
512#if ARGON_USE_COMPILER_EXTENSIONS
513 return vec_ - b.vec_ * c;
514#else
515 return simd::multiply_subtract(vec_, b, c);
516#endif
517 }
518
522
523#ifndef ARGON_PLATFORM_MVE
527 return simd::multiply_subtract_lane(vec_, b.vec(), c.vec(), c.lane());
528 }
529#endif
530
533 ace argon_type MultiplyFixedQMax(argon_type v) const { return simd::multiply_double_saturate_high(vec_, v); }
534
537 ace argon_type MultiplyFixedQMax(scalar_type s) const { return simd::multiply_double_saturate_high(vec_, s); }
538
539#ifndef ARGON_PLATFORM_MVE
543 return simd::multiply_double_saturate_high_lane(vec_, l.vec(), l.lane());
544 }
545#endif
546
550 return simd::multiply_double_round_saturate_high(vec_, v);
551 }
552
556 return simd::multiply_double_round_saturate_high(vec_, s);
557 }
558
559#ifndef ARGON_PLATFORM_MVE
563 return simd::multiply_double_round_saturate_high_lane(vec_, l.vec(), l.lane());
564 }
565#endif
566
568 ace argon_type Absolute() const { return simd::abs(vec_); }
569
573 requires std::floating_point<scalar_type> || std::is_same_v<scalar_type, uint32_t>
574 {
575#ifdef ARGON_PLATFORM_MVE
576 if constexpr (std::is_same_v<scalar_type, uint32_t>) {
577 std::numeric_limits<uint32_t>::max() / vec_;
578 } else {
579 return 1.f / vec_;
580 }
581#else
582 return simd::reciprocal_estimate(vec_);
583#endif
584 }
585
589 requires std::floating_point<scalar_type> || std::is_same_v<scalar_type, uint32_t>
590 {
591#ifdef ARGON_PLATFORM_MVE
592 if constexpr (std::is_same_v<scalar_type, uint32_t>) {
593 return std::numeric_limits<uint32_t>::max() / (vec_ * vec_);
594 } else {
595 return 1.f / (vec_ * vec_);
596 }
597#else
598 return simd::reciprocal_sqrt_estimate(vec_);
599#endif
600 }
601
606 requires std::floating_point<scalar_type>
607 {
608#ifdef ARGON_PLATFORM_MVE
609 return 2.f - vec_ * b.vec_;
610#else
611 return simd::reciprocal_step(vec_, b.vec_);
612#endif
613 }
614
619 requires std::floating_point<scalar_type>
620 {
621#ifdef ARGON_PLATFORM_MVE
622 return (3.f - vec_ * b.vec_) * 0.5f;
623#else
624 return simd::reciprocal_sqrt_step(vec_, b.vec_);
625#endif
626 }
627
631 ace argon_type ReciprocalEstimateRefine(int n_iters = 1) const
632 requires std::floating_point<scalar_type>
633 {
635 for (int i = 0; i < n_iters; ++i) {
636 est = est * ReciprocalStep(est);
637 }
638 return est;
639 }
640
644 ace argon_type ReciprocalSqrtEstimateRefine(int n_iters = 1) const
645 requires std::floating_point<scalar_type>
646 {
648 for (int i = 0; i < n_iters; ++i) {
649 est = est * (*this * est).ReciprocalSqrtStep(est);
650 }
651 return est;
652 }
653
656 template <typename arg_type>
657 requires(is_one_of<arg_type, argon_type, scalar_type, lane_type> || std::is_convertible_v<arg_type, argon_type> ||
658 std::is_convertible_v<arg_type, scalar_type>)
659 ace argon_type MultiplyAddFixedQMax(argon_type b, arg_type c) const {
660 return Add(b.MultiplyFixedQMax(c));
661 }
662
665 template <typename arg_type>
666 requires(is_one_of<arg_type, argon_type, scalar_type, lane_type> || std::is_convertible_v<arg_type, argon_type> ||
667 std::is_convertible_v<arg_type, scalar_type>)
669 return Add(b.MultiplyRoundFixedQMax(c));
670 }
671
672#ifdef __aarch64__
674 ace argon_type Divide(argon_type b) const {
675 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
676 return vec_ / b.vec_;
677 } else {
678 return simd::divide(vec_, b);
679 }
680 }
681#else
684 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
685 return vec_ / b.vec_;
686 } else {
687 return this->map2(b, [](scalar_type lane1, scalar_type lane2) { return lane1 / lane2; });
688 }
689 }
690#endif
691
695 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
696 return vec_ % b.vec_;
697 } else if constexpr (std::floating_point<scalar_type>) {
698 return this->map2(b, [](scalar_type lane1, scalar_type lane2) { return std::fmod(lane1, lane2); });
699 } else {
700 return this->map2(b, [](scalar_type lane1, scalar_type lane2) { return lane1 % lane2; });
701 }
702 }
703
707 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
708 return vec_ % b;
709 } else {
710 return this->map([b](scalar_type lane1) { return std::fmod(lane1, b); });
711 }
712 }
713
716 ace argon_type Max(argon_type b) const {
717 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
718 return vec_ > b.vec_ ? vec_ : b.vec_;
719 } else {
720 return simd::max(vec_, b);
721 }
722 }
723
725 ace argon_type Min(argon_type b) const {
726 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
727 return vec_ < b.vec_ ? vec_ : b.vec_;
728 } else {
729 return simd::min(vec_, b);
730 }
731 }
732
735 ace argon_bool_type Equal(argon_type b) const { return simd::equal(vec_, b); }
736
739 ace argon_bool_type GreaterThanOrEqual(argon_type b) const { return simd::greater_than_or_equal(vec_, b); }
740
743 ace argon_bool_type LessThanOrEqual(argon_type b) const { return simd::less_than_or_equal(vec_, b); }
744
747 ace argon_bool_type GreaterThan(argon_type b) const { return simd::greater_than(vec_, b); }
748
751 ace argon_bool_type LessThan(argon_type b) const { return simd::less_than(vec_, b); }
752
755 ace argon_type ShiftLeft(helpers::ArgonFor_t<simd::make_signed_t<Bool_t<VectorType>>> b) const
756 requires std::is_integral_v<scalar_type>
757 {
758 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
759 return vec_ << b.vec_;
760 } else {
761 return simd::shift_left(vec_, b.vec_);
762 }
763 }
764
767 ace argon_type ShiftLeft(std::make_signed_t<simd::Scalar_t<Bool_t<VectorType>>> n) const
768 requires std::is_integral_v<scalar_type>
769 {
770 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
771 return vec_ << n;
772 } else {
774 return simd::shift_left(vec_, b.vec_);
775 }
776 }
777
780 template <int n>
781 ace argon_type ShiftLeft() const {
782 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
783 return vec_ << n;
784 } else {
785 return simd::shift_left<n>(vec_);
786 }
787 }
788
790 ace argon_type ShiftLeftSaturate(helpers::ArgonFor_t<simd::make_signed_t<Bool_t<VectorType>>> b) const
791 requires(std::is_integral_v<scalar_type>)
792 {
793 return simd::shift_left_saturate(vec_, b);
794 }
795
797 ace argon_type ShiftLeftRound(argon_type b) const { return simd::shift_left_round(vec_, b); }
798
800 ace argon_type ShiftLeftRoundSaturate(argon_type b) const { return simd::shift_left_round_saturate(vec_, b); }
801
803 template <int n>
805 return simd::shift_left_saturate<n>(vec_);
806 }
807
813 template <int n>
815 return simd::shift_left_insert<n>(vec_, b);
816 }
817
819 template <int n>
820 ace argon_type ShiftRight() const {
821 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
822 return vec_ >> n;
823 } else {
824 return simd::shift_right<n>(vec_);
825 }
826 }
827
829 template <int n>
831 return simd::shift_right_round<n>(vec_);
832 }
833
837 template <int n>
839#ifdef ARGON_PLATFORM_MVE
840 return vec_ + (b >> n);
841#else
842 return simd::shift_right_accumulate<n>(vec_, b);
843#endif
844 }
845
849 template <int n>
851#ifdef ARGON_PLATFORM_MVE
852 return vec_ + mve::shift_right_round<n>(b);
853#else
854 return simd::shift_right_accumulate_round<n>(vec_, b);
855#endif
856 }
857
861 template <int n>
863 return simd::shift_right_insert<n>(vec_, b);
864 }
865
867 ace static argon_type Load(const scalar_type* ptr) {
868#ifdef ARGON_PLATFORM_MVE
869 return mve::load1(ptr);
870#else
871 return neon::load1<VectorType>(ptr);
872#endif
873 }
874
876 ace static argon_type LoadCopy(const scalar_type* ptr) {
877#ifdef ARGON_PLATFORM_MVE
878 scalar_type val = *ptr;
879 VectorType vec;
880 utility::constexpr_for<0, lanes, 1>([val, &vec]<int i>() { vec[i] = val; });
881#else
882 return simd::load1_duplicate<VectorType>(ptr);
883#endif
884 }
885
892 const scalar_type* base,
893 helpers::ArgonFor_t<simd::make_unsigned_t<Bool_t<VectorType>>> offset_vector) {
894#ifdef ARGON_PLATFORM_MVE
895 static_assert(
896 sizeof(scalar_type) == 1 || sizeof(scalar_type) == 2 || sizeof(scalar_type) == 4 || sizeof(scalar_type) == 8,
897 "Unsupported size for gather load");
898
899 if constexpr (sizeof(scalar_type) == 1) {
900 return mve::load_byte_gather_offset(base, offset_vector);
901 } else if constexpr (sizeof(scalar_type) == 2) {
902 return mve::load_halfword_gather_offset(base, offset_vector);
903 } else if constexpr (sizeof(scalar_type) == 4) {
904 return mve::load_word_gather_offset(base, offset_vector);
905 } else if constexpr (sizeof(scalar_type) == 8) {
906 return mve::load_doubleword_gather_offset(base, offset_vector);
907 }
908#else
909 argon_type destination;
910 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
911 auto lane_val = neon::get_lane<i>(offset_vector);
912 // lane_val is a *byte* offset; address by bytes (scalar_type* arithmetic
913 // would scale by sizeof a second time).
914 auto* addr = reinterpret_cast<const scalar_type*>(reinterpret_cast<const char*>(base) + lane_val);
915 destination = destination.template LoadToLane<i>(addr);
916 });
917 return destination;
918#endif
919 }
920
927 const scalar_type* base,
928 helpers::ArgonFor_t<simd::make_unsigned_t<Bool_t<VectorType>>> offset_vector) {
929#ifdef ARGON_PLATFORM_MVE
930 static_assert(
931 sizeof(scalar_type) == 1 || sizeof(scalar_type) == 2 || sizeof(scalar_type) == 4 || sizeof(scalar_type) == 8,
932 "Unsupported size for gather load");
933
934 if constexpr (sizeof(scalar_type) == 1) {
935 return mve::load_byte_gather_offset(base, offset_vector);
936 } else if constexpr (sizeof(scalar_type) == 2) {
937 return mve::load_halfword_gather_offset(base, offset_vector * sizeof(scalar_type));
938 } else if constexpr (sizeof(scalar_type) == 4) {
939 return mve::load_word_gather_offset(base, offset_vector * sizeof(scalar_type));
940 } else if constexpr (sizeof(scalar_type) == 8) {
941 return mve::load_doubleword_gather_offset(base, offset_vector * sizeof(scalar_type));
942 }
943#else
944 argon_type destination;
945 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
946 auto lane_val = neon::get_lane<i>(offset_vector);
947 destination = destination.template LoadToLane<i>(base + lane_val);
948 });
949 return destination;
950#endif
951 }
952
956 template <size_t lane>
958 return ConstLane<lane, VectorType>{vec_}.Load(ptr);
959 }
960
967 template <size_t stride>
968 ace static std::array<argon_type, stride> LoadInterleaved(const scalar_type* ptr) {
969#ifdef ARGON_PLATFORM_MVE
970 static_assert(stride == 2 || stride == 4,
971 "De-interleaving Loads can only be performed with a stride of 2, 3, or 4");
972 if constexpr (stride == 2) {
973 return argon::to_array(mve::load2(ptr).val);
974 } else if constexpr (stride == 4) {
975 return argon::to_array(mve::load4(ptr).val);
976 }
977#else
978 static_assert(stride > 1 && stride < 5, "De-interleaving Loads can only be performed with a stride of 2, 3, or 4");
979 using multivec_type = simd::MultiVector_t<VectorType, stride>;
980 if constexpr (stride == 2) {
981 return argon::to_array(neon::load2<multivec_type>(ptr).val);
982 } else if constexpr (stride == 3) {
983 return argon::to_array(neon::load3<multivec_type>(ptr).val);
984 } else if constexpr (stride == 4) {
985 return argon::to_array(neon::load4<multivec_type>(ptr).val);
986 }
987#endif
988 }
989
995 template <size_t stride>
996 ace static std::array<argon_type, stride> LoadCopyInterleaved(const scalar_type* ptr) {
997#ifdef ARGON_PLATFORM_MVE
998 static_assert(stride == 2 || stride == 4,
999 "De-interleaving LoadCopy can only be performed with a stride of 2, 3, or 4");
1000 if constexpr (stride == 2) {
1001 return {mve::duplicate(*ptr++), mve::duplicate(*ptr++)};
1002 } else if constexpr (stride == 4) {
1003 return {mve::duplicate(*ptr++), mve::duplicate(*ptr++), mve::duplicate(*ptr++), mve::duplicate(*ptr)};
1004 }
1005#else
1006 static_assert(stride > 1 && stride < 5,
1007 "De-interleaving LoadCopy can only be performed with a stride of 2, 3, or 4");
1008 using multivec_type = simd::MultiVector<VectorType, stride>::type;
1009 if constexpr (stride == 2) {
1010 return argon::to_array(simd::load2_duplicate<multivec_type>(ptr).val);
1011 } else if constexpr (stride == 3) {
1012 return argon::to_array(simd::load3_duplicate<multivec_type>(ptr).val);
1013 } else if constexpr (stride == 4) {
1014 return argon::to_array(simd::load4_duplicate<multivec_type>(ptr).val);
1015 }
1016#endif
1017 }
1018
1025 template <size_t LaneIndex, size_t Stride>
1026 ace static std::array<argon_type, Stride> LoadToLaneInterleaved(simd::MultiVector_t<VectorType, Stride> multi,
1027 const scalar_type* ptr) {
1028 static_assert(Stride > 1 && Stride < 5, "De-interleaving Loads can only be performed with a stride of 2, 3, or 4");
1029#ifdef ARGON_PLATFORM_MVE
1030 auto out = multi;
1031 utility::constexpr_for<0, Stride, 1>([&]<int i>() { //<
1032 out.val[i][LaneIndex] = ptr[i];
1033 });
1034 return argon::to_array(out.val);
1035#else
1036 if constexpr (Stride == 2) {
1037 if constexpr (simd::is_quadword_v<VectorType>) {
1038 return argon::to_array(simd::load2_lane_quad<LaneIndex>(ptr, multi).val);
1039 } else {
1040 return argon::to_array(simd::load2_lane<LaneIndex>(ptr, multi).val);
1041 }
1042 } else if constexpr (Stride == 3) {
1043 if constexpr (simd::is_quadword_v<VectorType>) {
1044 return argon::to_array(simd::load3_lane_quad<LaneIndex>(ptr, multi).val);
1045 } else {
1046 return argon::to_array(simd::load3_lane<LaneIndex>(ptr, multi).val);
1047 }
1048 } else if constexpr (Stride == 4) {
1049 if constexpr (simd::is_quadword_v<VectorType>) {
1050 return argon::to_array(simd::load4_lane_quad<LaneIndex>(ptr, multi).val);
1051 } else {
1052 return argon::to_array(simd::load4_lane<LaneIndex>(ptr, multi).val);
1053 }
1054 }
1055#endif
1056 }
1057
1059 template <size_t lane, size_t stride>
1060 ace static std::array<argon_type, stride> LoadToLaneInterleaved(std::array<argon_type, stride> multi,
1061 const scalar_type* ptr) {
1062 using multivec_type = simd::MultiVector_t<VectorType, stride>;
1063 return LoadToLaneInterleaved<lane, stride>(*(multivec_type*)multi.data(), ptr);
1064 }
1065
1076 template <size_t stride>
1077 ace static std::array<argon_type, stride> LoadGatherOffsetIndexInterleaved(
1078 const scalar_type* base_ptr,
1079 helpers::ArgonFor_t<simd::make_unsigned_t<Bool_t<VectorType>>> offset_vector) {
1080 static_assert(stride > 1 && stride < 5, "De-interleaving Loads can only be performed with a stride of 2, 3, or 4");
1081 std::array<argon_type, stride> multi{};
1082 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1083 auto lane_val = simd::get_lane<i>(offset_vector);
1084 multi = LoadToLaneInterleaved<i, stride>(multi, base_ptr + (lane_val * stride));
1085 });
1086 return multi;
1087 }
1088
1096 template <size_t n>
1097 ace static std::array<argon_type, n> LoadMulti(const scalar_type* ptr) {
1098 static_assert(n > 1 && n < 5, "LoadMulti can only be performed with a size of 2, 3, or 4");
1099#ifdef ARGON_PLATFORM_MVE
1100 std::array<argon_type, n> multi{};
1101 utility::constexpr_for<0, n, 1>([&]<int i>() { //<
1102 multi[i] = *ptr;
1103 ptr += lanes;
1104 });
1105 return multi;
1106#else
1107#if defined(__clang__) || (__GNUC__ > 13)
1108 using multi_type = simd::MultiVector_t<VectorType, n>;
1109 if constexpr (n == 2) {
1110 return argon::to_array(simd::load1_x2<multi_type>(ptr).val);
1111 } else if constexpr (n == 3) {
1112 return argon::to_array(simd::load1_x3<multi_type>(ptr).val);
1113 } else if constexpr (n == 4) {
1114 return argon::to_array(simd::load1_x4<multi_type>(ptr).val);
1115 }
1116#else
1117 // load1 is a return-type-only template, so the element type must be named
1118 // explicitly — `simd::load1(ptr)` cannot deduce it (fails to compile on MSVC).
1119 if constexpr (n == 2) {
1120 auto a = simd::load1<VectorType>(ptr);
1121 auto b = simd::load1<VectorType>(ptr + lanes);
1122 return {a, b};
1123 } else if constexpr (n == 3) {
1124 auto a = simd::load1<VectorType>(ptr);
1125 auto b = simd::load1<VectorType>(ptr + lanes);
1126 auto c = simd::load1<VectorType>(ptr + 2 * lanes);
1127 return {a, b, c};
1128 } else if constexpr (n == 4) {
1129 auto a = simd::load1<VectorType>(ptr);
1130 auto b = simd::load1<VectorType>(ptr + lanes);
1131 auto c = simd::load1<VectorType>(ptr + 2 * lanes);
1132 auto d = simd::load1<VectorType>(ptr + 3 * lanes);
1133 return {a, b, c, d};
1134 }
1135#endif
1136#endif
1137 }
1138
1141 ace void StoreTo(scalar_type* ptr) const { simd::store1(ptr, vec_); }
1142
1146 template <int LaneIndex>
1147 ace void StoreLaneTo(scalar_type* ptr) {
1148#ifdef ARGON_PLATFORM_MVE
1149 *ptr = vec_[LaneIndex];
1150#else
1151 simd::store1_lane<LaneIndex>(ptr, vec_);
1152#endif
1153 }
1154
1155#ifndef ARGON_PLATFORM_MVE
1157
1161 ace argon_type PairwiseAdd(argon_type b) const { return simd::pairwise_add(vec_, b); }
1162
1166 ace argon_type PairwiseMax(argon_type b) const { return simd::pairwise_max(vec_, b); }
1167
1171 ace argon_type PairwiseMin(argon_type b) const { return simd::pairwise_min(vec_, b); }
1172#endif
1173
1175
1178 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
1179 return ~vec_;
1180 } else {
1181 return simd::bitwise_not(vec_);
1182 }
1183 }
1184
1187 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
1188 return vec_ & b.vec_;
1189 } else {
1190 return simd::bitwise_and(vec_, b);
1191 }
1192 }
1193
1196 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
1197 return vec_ | b.vec_;
1198 } else {
1199 return simd::bitwise_or(vec_, b);
1200 }
1201 }
1202
1205 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
1206 return vec_ ^ b.vec_;
1207 } else {
1208 return simd::bitwise_xor(vec_, b);
1209 }
1210 }
1211
1215 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
1216 return vec_ | ~b.vec_;
1217 } else {
1218 return simd::bitwise_or_not(vec_, b);
1219 }
1220 }
1221
1225 if constexpr (ARGON_USE_COMPILER_EXTENSIONS) {
1226 return vec_ & ~b.vec_;
1227 } else {
1228 return simd::bitwise_clear(vec_, b);
1229 }
1230 }
1231
1234
1235#ifndef ARGON_PLATFORM_MVE
1238 template <typename ArgType>
1239 requires std::is_unsigned_v<scalar_type>
1240 ace argon_type BitwiseSelect(ArgType true_value, ArgType false_value) const {
1241 return simd::bitwise_select(vec_, true_value, false_value);
1242 }
1243
1245 template <typename ArgType>
1246 requires std::is_unsigned_v<scalar_type>
1247 ace argon_type Select(ArgType true_value, ArgType false_value) const {
1248 return simd::bitwise_select(true_value, false_value);
1249 }
1250
1253 ace predicate_type CompareTestNonzero(argon_type b) const { return simd::compare_test_nonzero(vec_, b); }
1254
1256 ace predicate_type TestNonzero() const { return simd::compare_test_nonzero(vec_, argon_type{1}); }
1257#endif
1258
1262 requires(std::is_integral_v<scalar_type>)
1263 {
1264 return simd::count_leading_sign_bits(vec_);
1265 }
1266
1269 ace argon_type CountLeadingZeroBits() const { return simd::count_leading_zero_bits(vec_); }
1270
1274#ifdef ARGON_PLATFORM_MVE
1275 auto new_vec = vec_;
1276 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1277 new_vec[i] = std::popcount(vec_[i]);
1278 });
1279 return new_vec;
1280#else
1281 return neon::count_active_bits(vec_);
1282#endif
1283 }
1284
1286 ace argon_type Popcount() const { return CountActiveBits(); }
1287
1291 template <int n>
1293#ifdef ARGON_PLATFORM_MVE
1294 auto new_vec = vec_;
1295 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1296 if (i < n) {
1297 new_vec[i] = b.vec_[i];
1298 }
1299 });
1300 return new_vec;
1301#else
1302 return simd::extract<n>(vec_, b);
1303#endif
1304 }
1305
1306 ace argon_type Reverse64bit() const { return simd::reverse_64bit(vec_); }
1307 ace argon_type Reverse32bit() const { return simd::reverse_32bit(vec_); }
1308 ace argon_type Reverse16bit() const { return simd::reverse_16bit(vec_); }
1309
1313 ace std::array<argon_type, 2> ZipWith(argon_type b) const {
1314#ifdef ARGON_PLATFORM_MVE
1315 std::array<argon_type, 2> new_vec;
1316 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1317 if (i % 2 == 0) {
1318 new_vec[0][i] = vec_[i / 2];
1319 new_vec[1][i] = vec_[(i + lanes) / 2];
1320 } else {
1321 new_vec[0][i] = b.vec_[i / 2];
1322 new_vec[1][i] = b.vec_[(i + lanes) / 2];
1323 }
1324 });
1325 return new_vec;
1326#else
1327 return argon::to_array(neon::zip(vec_, b.vec()).val);
1328#endif
1329 }
1330
1334 std::array<argon_type, 2> UnzipWith(argon_type b) {
1335#ifdef ARGON_PLATFORM_MVE
1336 std::array<argon_type, 2> new_vec;
1337 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1338 if ((i * 2) < lanes) {
1339 new_vec[0][i] = vec_[i * 2];
1340 new_vec[1][i] = vec_[i * 2 + 1];
1341 } else {
1342 new_vec[0][i] = b.vec_[i * 2];
1343 new_vec[1][i] = b.vec_[i * 2 + 1];
1344 }
1345 });
1346 return new_vec;
1347#else
1348 return argon::to_array(neon::unzip(vec_, b.vec()).val);
1349#endif
1350 }
1351
1354 // {b0, b1, b2, b3}}
1356 // {a1, b1, a3, b3}}
1357 std::array<argon_type, 2> TransposeWith(argon_type b) const {
1358#ifdef ARGON_PLATFORM_MVE
1359 std::array<argon_type, 2> new_vec;
1360 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1361 if (i % 2 == 1) {
1362 new_vec[0][i] = vec_[i];
1363 new_vec[1][i] = vec_[i + 1];
1364 } else {
1365 new_vec[0][i] = b.vec_[i + 1];
1366 new_vec[1][i] = b.vec_[i];
1367 }
1368 });
1369 return new_vec;
1370#else
1371 return argon::to_array(simd::transpose(vec_, b.vec()).val);
1372#endif
1373 }
1374
1376 ace static int size() { return lanes; }
1377
1378 template <typename FuncType>
1379 requires std::convertible_to<FuncType, std::function<scalar_type(scalar_type)>>
1380 ace argon_type map(FuncType body) const {
1381 VectorType out;
1382 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1383 out[i] = body(vec_[i]);
1384 });
1385 return out;
1386 }
1387
1388 template <typename FuncType>
1389 requires std::convertible_to<FuncType, std::function<scalar_type(scalar_type, int)>>
1390 ace argon_type map_with_index(FuncType body) const {
1391 VectorType out;
1392 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1393 out[i] = body(vec_[i], i);
1394 });
1395 return out;
1396 }
1397
1398 template <typename FuncType>
1399 requires std::convertible_to<FuncType, std::function<scalar_type(scalar_type, scalar_type)>>
1400 ace argon_type map2(argon_type other, FuncType body) const {
1401 VectorType out;
1402 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1403 out[i] = body(vec_[i], other.vec_[i]);
1404 });
1405 return out;
1406 }
1407
1408 template <typename FuncType>
1409 requires std::convertible_to<FuncType, std::function<void(scalar_type&)>>
1410 ace argon_type each_lane(FuncType body) {
1411 VectorType out = vec_;
1412 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1413 // A vector subscript (out[i]) is not an lvalue a non-const reference can bind to under
1414 // Clang (GCC accepts it as an extension). Round-trip through a scalar so the callback's
1415 // scalar_type& binds to a real object, then write the mutated value back.
1416 scalar_type lane = out[i];
1417 body(lane);
1418 out[i] = lane;
1419 });
1420 return out;
1421 }
1422
1423 template <typename FuncType>
1424 requires std::convertible_to<FuncType, std::function<void(scalar_type&, int)>>
1425 ace argon_type each_lane_with_index(FuncType body) {
1426 VectorType out = vec_;
1427 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1428 // See each_lane: a non-const reference cannot bind to a vector subscript under Clang.
1429 scalar_type lane = out[i];
1430 body(lane, i);
1431 out[i] = lane;
1432 });
1433 return out;
1434 }
1435
1436 template <typename FuncType>
1437 requires std::convertible_to<FuncType, std::function<void()>>
1438 ace void if_lane(FuncType true_branch) {
1439 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1440 if (vec_[i] != 0) {
1441 true_branch();
1442 }
1443 });
1444 }
1445
1446 template <typename FuncType>
1447 requires std::convertible_to<FuncType, std::function<void()>>
1448 ace void if_else_lane(FuncType true_branch, FuncType false_branch) {
1449 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1450 if (vec_[i] != 0) {
1451 true_branch();
1452 } else {
1453 false_branch();
1454 }
1455 });
1456 }
1457
1458 template <typename FuncType>
1459 requires std::convertible_to<FuncType, std::function<void(int)>>
1460 ace void if_lane_with_index(FuncType true_branch) {
1461 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1462 if (vec_[i] != 0) {
1463 true_branch(i);
1464 }
1465 });
1466 }
1467
1468 template <typename FuncType1, typename FuncType2>
1469 requires std::convertible_to<FuncType1, std::function<void(int)>> &&
1470 std::convertible_to<FuncType2, std::function<void(int)>>
1471 ace void if_else_lane_with_index(FuncType1 true_branch, FuncType2 false_branch) {
1472 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1473 if (vec_[i] != 0) {
1474 true_branch(i);
1475 } else {
1476 false_branch(i);
1477 }
1478 });
1479 }
1480
1481 ace bool any() {
1482 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1483 if (vec_[i]) {
1484 return true;
1485 }
1486 });
1487 return false;
1488 }
1489
1490 ace bool all() {
1491#ifdef ARGON_PLATFORM_MVE
1492 return mve::max_reduce_max(vec_, vec_) != 0;
1493#else
1494 auto nonzero = TestNonzero();
1495 utility::constexpr_for<0, lanes, 1>([&]<int i>() { //<
1496 if (nonzero[i] == 0) {
1497 return false;
1498 }
1499 });
1500 return true;
1501#endif
1502 }
1503
1504 template <std::size_t Index>
1505 std::tuple_element_t<Index, argon_type> get() {
1506#ifdef ARGON_PLATFORM_MVE
1507 return vec_[Index];
1508#else
1509 return GetLane<Index>();
1510#endif
1511 }
1512
1513 protected:
1514 template <std::size_t... Ints>
1515 ace static argon_type IotaHelper(scalar_type start, std::index_sequence<Ints...>) {
1516 return VectorType{static_cast<scalar_type>(start + Ints)...};
1517 }
1518
1519 VectorType vec_;
1520};
1521
1522} // namespace argon
1523
1527namespace std {
1528template <typename T>
1529struct tuple_size<argon::Vector<T>> {
1530 static constexpr size_t value = argon::Vector<T>::lanes;
1531};
1532
1533template <size_t Index, typename T>
1534struct tuple_element<Index, argon::Vector<T>> {
1535 static_assert(Index < argon::Vector<T>::lanes);
1537};
1538} // namespace std
1539
1540#undef ace
1541#undef simd
Provides utility templates and concepts for type traits and compile-time iteration.
A 128-bit SIMD vector wrapping a scalar type, providing arithmetic, logical, and data-movement operat...
Definition argon_full.hpp:29
Represents a single lane of a SIMD vector with the lane index known at compile time.
Definition lane.hpp:46
ace int lane()
On ARM32, return the local lane index within the 64-bit half-register returned by vec().
Definition lane.hpp:95
ace neon::Vec64_t< scalar_type > vec()
On ARM32, return the 64-bit half-register that contains this lane.
Definition lane.hpp:83
ace scalar_type Get() const
Get the scalar value of this lane.
Definition lane.hpp:74
ace argon_type Load(const scalar_type *ptr)
Load a scalar from ptr into this lane and return the updated vector.
Definition lane.hpp:60
Represents a single lane of a SIMD vector with a runtime-determined index.
Definition lane.hpp:117
ace int lane()
On ARM32, return the local lane index within the 64-bit half-register returned by vec().
Definition lane.hpp:162
ace neon::Vec64_t< scalar_type > vec()
On ARM32, return the 64-bit half-register that contains this lane.
Definition lane.hpp:150
ace scalar_type Get() const
Get the scalar value of this lane.
Definition lane.hpp:139
ace argon_type PairwiseMin(argon_type b) const
Select the maximum of each pair of lanes in the two vectors.
Definition vector.hpp:1171
Lane< simd::Vec128_t< ScalarType > > lane_type
Definition vector.hpp:54
ace argon_type MultiplySubtract(argon_type b, lane_type c) const
Multiply a vector by a lane value and subtract from a third vector.
Definition vector.hpp:526
ace Vector(VectorType vector)
Constructs a Vector from a SIMD vector type.
Definition vector.hpp:74
simd::Vec128_t< ScalarType > vector_type
Definition vector.hpp:56
ace argon_type Modulo(argon_type b) const
Get the modulo of two vectors.
Definition vector.hpp:694
ace argon_bool_type operator<(argon_type b) const
Compare two vectors, checking if this vector is less than the other.
Definition vector.hpp:225
ace argon_type ShiftLeftRound(argon_type b) const
Shift the elements of the vector to the left by a specified number of bits, rounding the result.
Definition vector.hpp:797
std::array< argon_type, 2 > TransposeWith(argon_type b) const
Perform a 2x2 matrix transpose on two vectors, returning two vectors of pairs.
Definition vector.hpp:1357
constexpr Vector(const Vector &other)=default
Copy constructor for the Vector class.
static ace std::array< argon_type, stride > LoadInterleaved(const scalar_type *ptr)
Load multiple vectors from a pointer, de-interleaving.
Definition vector.hpp:968
static ace argon_type Iota(scalar_type start)
Constructs a Vector from an incrementing sequence.
Definition vector.hpp:161
static ace argon_type FromScalar(scalar_type scalar)
Definition vector.hpp:110
ace argon_type Multiply(scalar_type b) const
Multiply a vector by a scalar value.
Definition vector.hpp:431
ace argon_type ReciprocalEstimateRefine(int n_iters=1) const
Compute a refined reciprocal estimate using Newton-Raphson iterations.
Definition vector.hpp:631
ace argon_type MultiplySubtract(argon_type b, argon_type c) const
Multiply two vectors and subtract from a third vector.
Definition vector.hpp:501
ace argon_type Extract(argon_type b) const
Extract n elements from the lower end of the operand, and the remaining elements from the top end of ...
Definition vector.hpp:1292
constexpr VectorType vec() const
Get the underlying SIMD vector.
Definition vector.hpp:279
ace argon_type ReciprocalEstimate() const
1 / value, using an estimate for speed
Definition vector.hpp:572
ace argon_type Multiply(argon_type b) const
Multiply two vectors.
Definition vector.hpp:422
ace argon_bool_type LessThanOrEqual(argon_type b) const
Compare the lanes of two vectors, setting the result lane's bits to ON if a is less than or equal to ...
Definition vector.hpp:743
ace argon_type operator--() const
Decrement the vector by 1 and return the result.
Definition vector.hpp:240
ace argon_type ShiftLeft(const int i) const
Shift the elements of the vector to the left by a specified number of bits.
Definition vector.hpp:358
static ace argon_type Load(const scalar_type *ptr)
Load a vector from a pointer.
Definition vector.hpp:867
ace argon_type operator+(argon_type b) const
Add a vector and return the result.
Definition vector.hpp:207
ace argon_type ShiftLeft(helpers::ArgonFor_t< simd::make_signed_t< Bool_t< VectorType > > > b) const
Shift the elemnets of the vector to the left by a specified number of bits.
Definition vector.hpp:755
ace argon_type Multiply(const_lane_type< LaneIndex > b) const
Multiply a vector by a lane value.
Definition vector.hpp:445
ace argon_type PairwiseAdd(argon_type b) const
Pairwise ops.
Definition vector.hpp:1161
ace argon_type MultiplyAdd(scalar_type b, argon_type c) const
Multiply a vector by a scalar value and add a third vector.
Definition vector.hpp:472
ace argon_bool_type operator>=(argon_type b) const
Compare two vectors, checking if this vector is greater than or equal to the other.
Definition vector.hpp:234
ace argon_type MultiplyAdd(argon_type b, lane_type c) const
Multiply a vector by a lane value and add a third vector.
Definition vector.hpp:477
ace argon_bool_type operator==(argon_type b) const
Compare two vectors for equality.
Definition vector.hpp:219
ace argon_type MultiplyAdd(argon_type b, argon_type c) const
Multiply two vectors and add a third vector.
Definition vector.hpp:452
ace argon_type BitwiseSelect(ArgType true_value, ArgType false_value) const
Bitwise select between two vectors, using the current vector as a mask.
Definition vector.hpp:1240
ace argon_type ShiftLeft(std::make_signed_t< simd::Scalar_t< Bool_t< VectorType > > > n) const
Shift the elements of the vector to the left by a specified number of bits.
Definition vector.hpp:767
ace argon_type BitwiseOrNot(argon_type b) const
Bitwise OR of the vector with the NOT of another vector.
Definition vector.hpp:1214
ace helpers::ArgonFor_t< simd::make_signed_t< Bool_t< VectorType > > > CountLeadingSignBits() const
Count the number of consecutive bits following the sign bit that are set to the same value as the sig...
Definition vector.hpp:1261
static ace argon_type FromLane(argon::ConstLane< LaneIndex, VectorType > lane)
Constructs a Vector from a ConstLane object.
Definition vector.hpp:136
ace argon_type AddSaturate(argon_type b) const
Adds two vectors, saturating the result.
Definition vector.hpp:389
std::array< argon_type, 2 > UnzipWith(argon_type b)
Unzip two vectors, returning two vectors of pairs.
Definition vector.hpp:1334
ace argon_type operator++() const
Increment the vector by 1 and return the result.
Definition vector.hpp:237
ace argon_type MultiplyAddFixedQMax(argon_type b, arg_type c) const
Multiply-add three fixed-point vectors, returning a fixed-point sum.
Definition vector.hpp:659
ace argon_type operator^(argon_type b) const
Bitwise XOR two vectors and return the result.
Definition vector.hpp:249
ace argon_type ReciprocalSqrtStep(argon_type b) const
Newton-Raphson step for reciprocal-sqrt refinement: (3 - a * b) / 2.
Definition vector.hpp:618
ace argon_bool_type Equal(argon_type b) const
Compare the lanes of two vectors, setting the result lane's bits to ON if are equal.
Definition vector.hpp:735
ace void StoreTo(scalar_type *ptr) const
Store the vector to a pointer.
Definition vector.hpp:1141
ConstLane< LaneIndex, simd::Vec128_t< ScalarType > > const_lane_type
Definition vector.hpp:53
ace argon_type MultiplyRoundFixedQMax(lane_type l) const
Multiply a fixed-point vector by a lane value, returning a fixed-point product.
Definition vector.hpp:562
ace argon_type CountActiveBits() const
Count the number of bits that are set to one in the vector.
Definition vector.hpp:1273
ace argon_type MultiplyFixedQMax(scalar_type s) const
Multiply a QMax fixed-point vector by a scalar value, returning a fixed-point product.
Definition vector.hpp:537
ace predicate_type CompareTestNonzero(argon_type b) const
Ands the current vector with the given vector, then checks if nonzero.
Definition vector.hpp:1253
static ace std::array< argon_type, stride > LoadToLaneInterleaved(std::array< argon_type, stride > multi, const scalar_type *ptr)
Load a value from a pointer into a vector at the lane index lane, de-interleaving.
Definition vector.hpp:1060
ace argon_type PairwiseMax(argon_type b) const
Select the maximum of each pair of lanes in the two vectors.
Definition vector.hpp:1166
ace argon_type operator/(argon_type b) const
Divide a vector and return the result.
Definition vector.hpp:216
ace argon_type BitwiseNot() const
Bitwise ops.
Definition vector.hpp:1177
ace argon_type Max(argon_type b) const
Compare the lanes of two vectors, copying the larger of each lane to the result.
Definition vector.hpp:716
static ace argon_type FromLane(argon::Lane< IntrinsicType > lane)
Definition vector.hpp:123
constexpr Vector & operator=(Vector &&other)=default
Move assignment operator for the Vector class.
ace argon_type ShiftLeftInsert(argon_type b) const
Shift the elements of the vector to the left by a specified number of bits, and then OR the result wi...
Definition vector.hpp:814
ace const lane_type GetLane(const size_t i) const
Get a single lane of the vector by index.
Definition vector.hpp:296
ace argon_type BitwiseAnd(argon_type b) const
Bitwise AND of the vector with another vector.
Definition vector.hpp:1186
ace argon_type MultiplyAdd(argon_type b, const_lane_type< LaneIndex > c) const
Multiply a vector by a lane value and add a third vector.
Definition vector.hpp:488
ace argon_type Modulo(scalar_type b) const
Get the modulo of a vector and a scalar value.
Definition vector.hpp:706
ace argon_type Popcount() const
Count the number of bits that are set to one in the vector.
Definition vector.hpp:1286
ace argon_bool_type LessThan(argon_type b) const
Compare the lanes of two vectors, setting the result lane's bits to ON if a is less than b.
Definition vector.hpp:751
ace argon_type ShiftRight(const int i) const
Shift the elements of the vector to the right by a specified number of bits.
Definition vector.hpp:355
ace argon_type ShiftLeftRoundSaturate(argon_type b) const
Shift the elements of the vector to the left by a specified number of bits, rounding and saturating t...
Definition vector.hpp:800
ace Vector(scalar_type scalar)
Constructs a Vector from a scalar value.
Definition vector.hpp:79
ace argon_type ShiftRight() const
Shift the elements of the vector to the right by a specified number of bits.
Definition vector.hpp:820
ace argon_type Negate() const
Bitwise negate the vector and return the result.
Definition vector.hpp:361
ace void StoreLaneTo(scalar_type *ptr)
Store a lane of the vector to a pointer.
Definition vector.hpp:1147
ace argon_type Multiply(lane_type b) const
Multiply a vector by a lane value.
Definition vector.hpp:441
ace argon_type MultiplySubtract(argon_type b, scalar_type c) const
Multiply a vector by a scalar value and subtract from a third vector.
Definition vector.hpp:511
ace argon_type MultiplyAdd(const_lane_type< LaneIndex > b, argon_type c) const
Multiply a vector by a lane value and add a third vector.
Definition vector.hpp:494
ace argon_type MultiplyRoundFixedQMax(scalar_type s) const
Multiply a fixed-point vector by a scalar value, returning a fixed-point product.
Definition vector.hpp:555
ace argon_bool_type GreaterThanOrEqual(argon_type b) const
Compare the lanes of two vectors, setting the result lane's bits to ON if a is greater than or equal ...
Definition vector.hpp:739
ace argon_bool_type operator>(argon_type b) const
Compare two vectors, checking if this vector is greater than the other.
Definition vector.hpp:228
ace argon_type operator<<(const int i) const
Shift the elements of the vector to the left by a specified number of bits.
Definition vector.hpp:270
ace argon_type AddHalve(argon_type b) const
Adds two vectors, halving the result.
Definition vector.hpp:380
static ace std::array< argon_type, stride > LoadGatherOffsetIndexInterleaved(const scalar_type *base_ptr, helpers::ArgonFor_t< simd::make_unsigned_t< Bool_t< VectorType > > > offset_vector)
Perform a Load-Gather of interleaved elements.
Definition vector.hpp:1077
ace argon_type Divide(argon_type b) const
Divide two vectors.
Definition vector.hpp:683
ace argon_type ShiftRightRound() const
Shift the elements of the vector to the right by a specified number of bits, rounding the result.
Definition vector.hpp:830
Bool_t< simd::Vec128_t< ScalarType > > predicate_type
Definition vector.hpp:58
static ace std::array< argon_type, stride > LoadCopyInterleaved(const scalar_type *ptr)
Load multiple vectors from a pointer, duplicating the value across all lanes.
Definition vector.hpp:996
static ace int size()
Get the number of elements.
Definition vector.hpp:1376
static ace argon_type LoadGatherOffsetBytes(const scalar_type *base, helpers::ArgonFor_t< simd::make_unsigned_t< Bool_t< VectorType > > > offset_vector)
Using a base address and a vector of offset bytes and a base pointer, create a new vector.
Definition vector.hpp:891
ace argon_bool_type GreaterThan(argon_type b) const
Compare the lanes of two vectors, setting the result lane's bits to ON if a is greater than b.
Definition vector.hpp:747
ace argon_type ReciprocalStep(argon_type b) const
Newton-Raphson step for reciprocal refinement: (2 - a * b) / 2.
Definition vector.hpp:605
ace std::array< argon_type, 2 > ZipWith(argon_type b) const
Zip two vectors together, returning two vectors of pairs.
Definition vector.hpp:1313
ace argon_type operator-(argon_type b) const
Subtract a vector and return the result.
Definition vector.hpp:210
ace argon_type MultiplyRoundAddFixedQMax(argon_type b, arg_type c) const
Multiply-round-add three fixed-point vectors, returning a fixed-point sum.
Definition vector.hpp:668
helpers::ArgonFor_t< simd::Vec128_t< ScalarType > > argon_type
Definition vector.hpp:57
static ace argon_type LoadScalar(const scalar_type *ptr)
Constructs a Vector from a scalar pointer.
Definition vector.hpp:104
ace argon_type ShiftRightAccumulateRound(argon_type b) const
Shift the elements of the b vector to the right by a specified number of bits, and then add the resul...
Definition vector.hpp:850
ace argon_type operator*(argon_type b) const
Multiply a vector and return the result.
Definition vector.hpp:213
ace predicate_type TestNonzero() const
Ands the current vector with the given vector, then checks if nonzero.
Definition vector.hpp:1256
static ace argon_type LoadCopy(const scalar_type *ptr)
Load a vector from a pointer, duplicating the value across all lanes.
Definition vector.hpp:876
ace argon_type LoadToLane(const scalar_type *ptr)
Load a lane from a pointer.
Definition vector.hpp:957
ace argon_type SubtractAbs(argon_type b) const
Subtract two vectors, taking the absolute value of the result.
Definition vector.hpp:409
ace argon_type ShiftLeft() const
Shift the elements of the vector to the left by a specified number of bits.
Definition vector.hpp:781
ace const_lane_type< lanes - 1 > LastLane()
Get the last lane of the vector.
Definition vector.hpp:352
ace argon_type ShiftLeftSaturate(helpers::ArgonFor_t< simd::make_signed_t< Bool_t< VectorType > > > b) const
Shift the elements of the vector to the left by a specified number of bits, saturating the result.
Definition vector.hpp:790
ace argon_type MultiplyFixedQMax(lane_type l) const
Multiply a QMax fixed-point vector by a lane value, returning a fixed-point product.
Definition vector.hpp:542
ace argon_type MultiplySubtract(scalar_type b, argon_type c) const
Multiply a vector by a scalar value and subtract from a third vector.
Definition vector.hpp:521
ace argon_bool_type operator<=(argon_type b) const
Compare two vectors, checking if this vector is less than or equal to the other.
Definition vector.hpp:231
ace argon_type ShiftLeftSaturate() const
Shift the elements of the vector to the left by a specified number of bits, saturating the result.
Definition vector.hpp:804
ace argon_type operator&(argon_type b) const
Bitwise AND two vectors and return the result.
Definition vector.hpp:243
ace argon_type MultiplyRoundFixedQMax(argon_type v) const
Multiply two fixed-point vectors, returning a fixed-point product.
Definition vector.hpp:549
ace argon_type SubtractSaturate(argon_type b) const
Subtract two vectors, saturating the result.
Definition vector.hpp:405
static ace std::array< argon_type, Stride > LoadToLaneInterleaved(simd::MultiVector_t< VectorType, Stride > multi, const scalar_type *ptr)
Load a value from a pointer into a vector at the lane index lane, de-interleaving.
Definition vector.hpp:1026
ace argon_type ReciprocalSqrtEstimateRefine(int n_iters=1) const
Compute a refined reciprocal-sqrt estimate using Newton-Raphson iterations.
Definition vector.hpp:644
static ace std::array< argon_type, n > LoadMulti(const scalar_type *ptr)
Load n vectors from a single contiguous set of memory.
Definition vector.hpp:1097
static ace argon_type LoadGatherOffsetIndex(const scalar_type *base, helpers::ArgonFor_t< simd::make_unsigned_t< Bool_t< VectorType > > > offset_vector)
Using a base address and a vector of offset indices and a base pointer, create a new vector.
Definition vector.hpp:926
helpers::ArgonFor_t< predicate_type > argon_bool_type
Definition vector.hpp:59
ace argon_type operator|(argon_type b) const
Bitwise OR two vectors and return the result.
Definition vector.hpp:246
ace argon_type MultiplyFixedQMax(argon_type v) const
Multiply two QMax fixed-point vectors, returning a fixed-point product.
Definition vector.hpp:533
ace argon_type MultiplyAdd(argon_type b, scalar_type c) const
Multiply a vector by a scalar value and add a third vector.
Definition vector.hpp:462
simd::Scalar_t< simd::Vec128_t< ScalarType > > scalar_type
Definition vector.hpp:55
ace const const_lane_type< LaneIndex > GetLane() const
Get a single lane of the vector by index.
Definition vector.hpp:334
ace argon_type Select(ArgType true_value, ArgType false_value) const
Bitwise select between two vectors, using the current vector as a mask.
Definition vector.hpp:1247
ace argon_type operator~() const
Bitwise NOT the vector and return the result.
Definition vector.hpp:252
ace Vector(argon::ConstLane< LaneIndex, VectorType > lane)
Constructs a Vector from a ConstLane object.
Definition vector.hpp:92
ace std::array< scalar_type, lanes > to_array()
Convert the vector to an array of scalar values.
Definition vector.hpp:286
ace argon_type Absolute() const
Get the absolute value of the vector.
Definition vector.hpp:568
static constexpr size_t lanes
Definition vector.hpp:62
ace lane_type operator[](const size_t i)
Access a lane of the vector by index.
Definition vector.hpp:258
ace argon_type BitwiseClear(argon_type b) const
Bitwise AND of the vector with the NOT of another vector.
Definition vector.hpp:1233
ace argon_type BitwiseAndNot(argon_type b) const
Bitwise AND of the vector with the NOT of another vector.
Definition vector.hpp:1224
ace argon_type ShiftRightAccumulate(argon_type b) const
Shift the elements of the b vector to the right by a specified number of bits, and then add the resul...
Definition vector.hpp:838
ace argon_type operator>>(const int i) const
Shift the elements of the vector to the right by a specified number of bits.
Definition vector.hpp:261
ace argon_type Add(argon_type b) const
Add two vectors.
Definition vector.hpp:370
ace argon_type BitwiseOr(argon_type b) const
Bitwise OR of the vector with another vector.
Definition vector.hpp:1195
ace argon_type ReciprocalSqrtEstimate() const
1 / sqrt(value), using an estimate for speed
Definition vector.hpp:588
constexpr Vector()=default
The default constructor for the Vector class.
ace const lane_type GetLane(const int i) const
Get a single lane of the vector by index.
Definition vector.hpp:314
constexpr Vector & operator=(const Vector &other)=default
Copy assignment operator for the Vector class.
static ace argon_type GenerateWithIndex(FuncType body)
Constructs a Vector from a function that generates values with an index.
Definition vector.hpp:193
ace argon_bool_type operator!=(argon_type b) const
Compare two vectors for inequality.
Definition vector.hpp:222
ace argon_type CountLeadingZeroBits() const
Count the number of consecutive top bits that are set to zero.
Definition vector.hpp:1269
ace argon_type Min(argon_type b) const
Compare the lanes of two vectors, copying the smaller of each lane to the result.
Definition vector.hpp:725
ace argon_type operator-() const
Negate the SIMD vector and return the result.
Definition vector.hpp:204
ace argon_type SubtractHalve(argon_type b) const
Subtract two vectors, halving the result.
Definition vector.hpp:402
ace argon_type MultiplyAdd(lane_type b, argon_type c) const
Multiply a vector by a lane value and add a third vector.
Definition vector.hpp:483
ace argon_type ShiftRightInsert(argon_type b) const
Shift the elements of the vector to the right by a specified number of bits, ORing the result with th...
Definition vector.hpp:862
ace argon_type SubtractAbsAdd(argon_type b, argon_type c) const
Subtract two vectors, taking the absolute value of the result and adding a third vector.
Definition vector.hpp:413
constexpr Vector(Vector &&other)=default
Move constructor for the Vector class.
ace argon_type Subtract(argon_type b) const
Subtract two vectors.
Definition vector.hpp:392
ace argon_type BitwiseXor(argon_type b) const
Bitwise XOR of the vector with another vector.
Definition vector.hpp:1204
ace Vector(argon::Lane< VectorType > lane)
Constructs a Vector from a Lane object.
Definition vector.hpp:85
static ace argon_type Generate(FuncType body)
Constructs a Vector from a function that generates values.
Definition vector.hpp:176
ace argon_type AddHalveRound(argon_type b) const
Adds two vectors, halving and rounding the result.
Definition vector.hpp:384
ace Lane< const VectorType > operator[](const size_t i) const
Access a lane of the vector by index.
Definition vector.hpp:255
Definition vector.hpp:36
Header file for SIMD features and platform detection.
typename ArgonFor< std::remove_cv_t< T > >::type ArgonFor_t
Helper alias to get the Argon type for a given vector type.
Definition argon_for.hpp:45
Lane deconstruction feature.
Definition argon_full.hpp:399
Helper functions to convert C-style arrays to std::array of Argon types, mimicking std::to_array.
constexpr std::array< helpers::ArgonFor_t< T >, N > to_array(T(&a)[N])
Convert a C-style array of vector types to a std::array of Argon types.
Definition to_array.hpp:29