Argon 0.1.0
Loading...
Searching...
No Matches
argon_full.hpp
1#pragma once
2#include <array>
3#include <numeric>
4#include <type_traits>
5#include "arm_simd.hpp"
6#include "helpers.hpp"
7#include "helpers/argon_for.hpp"
8#include "vector.hpp"
9
10#ifdef __ARM_FEATURE_MVE
11#define simd mve
12#else
13#define simd neon
14#endif
15
16#ifdef __clang__
17#define ace [[nodiscard]] [[gnu::always_inline]] constexpr
18#else
19#define ace [[nodiscard]] [[gnu::always_inline]] inline
20#endif
21
22template <typename ScalarType>
23 requires std::is_arithmetic_v<ScalarType>
24class Argon : public argon::Vector<simd::Vec128_t<ScalarType>> {
26
27 public:
28 using vector_type = simd::Vec128_t<ScalarType>;
29 using lane_type = const argon::Lane<vector_type>;
30
31 static_assert(simd::is_quadword_v<vector_type>);
32
33 static constexpr size_t bytes = 16;
34 static constexpr size_t lanes = bytes / sizeof(ScalarType);
35
36 using argon::Vector<vector_type>::Vector;
37 ace Argon(argon::Vector<vector_type> vec) : T{std::move(vec)} {};
38 ace Argon(std::array<ScalarType, 4> value_list) : T{T::Load(value_list.data())} {};
39 ace Argon(ArgonHalf<ScalarType> low, ArgonHalf<ScalarType> high) : T{Combine(low, high)} {};
40
41#ifndef ARGON_PLATFORM_MVE
42 ace Argon(argon::Lane<vector_type> b) : T{b} {};
43 ace Argon(argon::ConstLane<0, vector_type> b) : T{b} {};
44#endif
45
46 template <simd::is_vector_type intrinsic_type>
47 ace Argon(argon::Lane<intrinsic_type> b) : T{b} {};
48
49 template <typename new_scalar_type>
50 ace Argon<new_scalar_type> As() const {
51 return simd::reinterpret<simd::Vec128_t<new_scalar_type>>(this->vec_);
52 }
53
54#ifndef ARGON_PLATFORM_MVE
55 ace static Argon<ScalarType> Combine(ArgonHalf<ScalarType> low, ArgonHalf<ScalarType> high) {
56 return simd::combine(low, high);
57 }
58
59 ace Argon<ScalarType> Reverse() {
60 auto rev_half = this->Reverse64bit();
61 return Combine(rev_half.GetHigh(), rev_half.GetLow());
62 }
63
64 template <typename U>
66 std::is_same_v<U, typename argon::helpers::NextSmaller<ScalarType>::type>
67 ace Argon<ScalarType> MultiplyAddLong(ArgonHalf<U> b, ArgonHalf<U> c) {
68 return simd::multiply_add_long(this->vec_, b, c);
69 }
70 template <typename U, typename C>
72 std::is_same_v<C, simd::Vec64_t<argon::helpers::NextSmaller_t<ScalarType>>>
73 ace Argon<ScalarType> MultiplyAddLong(ArgonHalf<U> b, C c) {
74 return simd::multiply_add_long(this->vec_, b, c);
75 }
76
77 template <typename U>
79 std::is_same_v<U, typename argon::helpers::NextSmaller<ScalarType>::type>
80 ace Argon<ScalarType> MultiplyAddLong(ArgonHalf<U> b, U c) {
81 return simd::multiply_add_long(this->vec_, b, c);
82 }
83
84 template <typename U>
86 std::is_same_v<U, typename argon::helpers::NextSmaller<ScalarType>::type>
87 ace Argon<ScalarType> MultiplyAddLong(ArgonHalf<U> b, typename ArgonHalf<U>::lane_type c) {
88 return simd::multiply_add_long(this->vec_, b, c.vec(), c.lane());
89 }
90
91 template <typename U>
93 std::is_same_v<U, typename argon::helpers::NextSmaller<ScalarType>::type>
94 ace Argon<ScalarType> MultiplySubtractLong(ArgonHalf<U> b, ArgonHalf<U> c) {
95 return simd::multiply_subtract_long(this->vec_, b, c);
96 }
97
98 template <typename U>
100 std::is_same_v<U, typename argon::helpers::NextSmaller<ScalarType>::type>
101 ace Argon<ScalarType> MultiplySubtractLong(ArgonHalf<U> b, U c) {
102 return simd::multiply_subtract_long(this->vec_, b, c);
103 }
104
105 template <typename U>
107 std::is_same_v<U, typename argon::helpers::NextSmaller<ScalarType>::type>
108 ace Argon<ScalarType> MultiplySubtractLong(ArgonHalf<U> b, typename ArgonHalf<U>::lane_type c) {
109 return simd::multiply_subtract_long(this->vec_, b, c.vec(), c.lane());
110 }
111
112 ace auto AddNarrow(Argon<ScalarType> b) const
114 {
115 auto result = simd::add_narrow(this->vec_, b);
116 return argon::helpers::ArgonFor_t<decltype(result)>{result};
117 }
118
119 ace auto AddRoundNarrow(Argon<ScalarType> b) const
121 {
122 auto result = simd::add_round_narrow(this->vec_, b);
123 return argon::helpers::ArgonFor_t<decltype(result)>{result};
124 }
125
126 ace auto SubtractNarrow(Argon<ScalarType> b) const
128 {
129 auto result = simd::subtract_narrow(this->vec_, b);
130 return argon::helpers::ArgonFor_t<decltype(result)>{result};
131 }
132
133 ace auto SubtractRoundNarrow(Argon<ScalarType> b) const
135 {
136 auto result = simd::subtract_round_narrow(this->vec_, b);
137 return argon::helpers::ArgonFor_t<decltype(result)>{result};
138 }
139
140 template <size_t n>
142 ace auto ShiftRightNarrow() const {
143 auto result = simd::shift_right_narrow<n>(this->vec_);
144 return argon::helpers::ArgonFor_t<decltype(result)>{result};
145 }
146
147 template <size_t n>
149 ace auto ShiftRightSaturateNarrow() const {
150 auto result = simd::shift_right_saturate_narrow<n>(this->vec_);
151 return argon::helpers::ArgonFor_t<decltype(result)>{result};
152 }
153
154 template <size_t n>
156 ace auto ShiftRightRoundSaturateNarrow() const {
157 auto result = simd::shift_right_round_saturate_narrow<n>(this->vec_);
158 return argon::helpers::ArgonFor_t<decltype(result)>{result};
159 }
160
161 template <size_t n>
163 ace auto ShiftRightRoundNarrow() const {
164 auto result = simd::shift_right_round_narrow<n>(this->vec_);
165 return argon::helpers::ArgonFor_t<decltype(result)>{result};
166 }
167
168 ace auto Narrow() const
170 {
171 auto result = simd::move_narrow(this->vec_);
172 return argon::helpers::ArgonFor_t<decltype(result)>{result};
173 }
174
175 ace auto SaturateNarrow() const
177 {
178 auto result = simd::move_saturate_narrow(this->vec_);
179 return argon::helpers::ArgonFor_t<decltype(result)>{result};
180 }
181
182 template <typename NextSmallerType>
184 std::is_same_v<NextSmallerType, argon::helpers::NextSmaller_t<ScalarType>>
185 ace Argon<ScalarType> MultiplyDoubleAddSaturateLong(ArgonHalf<NextSmallerType> b, ArgonHalf<NextSmallerType> c) {
186 return neon::multiply_double_add_saturate_long(this->vec_, b, c);
187 }
188
189 ace ArgonHalf<ScalarType> GetHigh() const { return simd::get_high(this->vec_); }
190 ace ArgonHalf<ScalarType> GetLow() const { return simd::get_low(this->vec_); }
191#endif
192
193 template <typename U>
194 ace Argon<U> ConvertTo() const {
195 return simd::convert<typename simd::Vec128<U>::type>(this->vec_);
196 }
197
198 template <typename U, int fracbits>
199 requires(std::is_same_v<U, uint32_t> || std::is_same_v<U, int32_t> || std::is_same_v<U, float>)
200 ace Argon<U> ConvertTo() const {
201 if constexpr (std::is_same_v<U, float>) {
202 return simd::convert_n<fracbits>(this->vec_);
203 } else if constexpr (std::is_unsigned_v<U>) {
204 return simd::convert_n_unsigned<fracbits>(this->vec_);
205 } else if constexpr (std::is_signed_v<U>) {
206 return simd::convert_n_signed<fracbits>(this->vec_);
207 }
208 }
209
210 ace Argon<ScalarType> Reverse() const {
211 Argon<ScalarType> rev = this->Reverse64bit(); // rev within dword
212 return Argon{rev.GetHigh(), rev.GetLow()}; // swap dwords
213 }
214
215 template <typename CommutableOpType>
216 ScalarType Reduce(CommutableOpType op) {
217 auto rev = this->SwapDoublewords();
218 auto sum = op(*this, rev);
219 if constexpr (lanes == 16) {
220 sum = op(*this, sum.Reverse16bit());
221 }
222 if constexpr (lanes == 8 || lanes == 16) {
223 sum = op(*this, sum.Reverse32bit());
224 }
225 if constexpr (lanes == 4 || lanes == 8 || lanes == 16) {
226 sum = op(*this, sum.Reverse64bit());
227 }
228 return sum[0];
229 }
230
231 ScalarType ReduceAdd() {
232#ifdef __aarch64__
233 return simd::reduce_add(this->vec_);
234#else
235 return this->Reduce([](auto a, auto b) { return a + b; });
236#endif
237 }
238
239 ScalarType ReduceMax() {
240#ifdef __aarch64__
241 return simd::reduce_max(this->vec_);
242#else
243 return this->Reduce([](auto a, auto b) { return std::max(a, b); });
244#endif
245 }
246
247 ScalarType ReduceMin() {
248#ifdef __aarch64__
249 return simd::reduce_min(this->vec_);
250#else
251 auto arr = this->to_array();
252 return std::reduce(arr.begin(), arr.end(), arr[0], [](auto a, auto b) { return std::min(a, b); });
253#endif
254 }
255
256#ifndef ARGON_PLATFORM_MVE
257 ace Argon<ScalarType> SwapDoublewords() { return Combine(GetHigh(), GetLow()); }
258#endif
259};
260
261template <typename... arg_types>
262 requires(sizeof...(arg_types) > 1)
263// Argon(arg_types...) -> Argon<arg_types...[0]>;
264Argon(arg_types...) -> Argon<std::tuple_element_t<0, std::tuple<arg_types...>>>;
265
266#ifndef ARGON_PLATFORM_MVE
267template <typename VectorType>
269
270template <typename VectorType>
272#endif
273
274template <typename ScalarType>
275 requires std::is_scalar_v<ScalarType>
276Argon(ScalarType) -> Argon<ScalarType>;
277
278template <typename V>
279 requires std::is_scalar_v<V>
280ace Argon<V> operator+(const V a, const Argon<V> b) {
281 return b.Add(a);
282}
283
284template <typename V>
285 requires std::is_scalar_v<V>
286ace Argon<V> operator-(const V a, const Argon<V> b) {
287 return Argon<V>{a}.Subtract(b);
288}
289
290template <typename V>
291 requires std::is_scalar_v<V>
292ace Argon<V> operator*(const V a, const Argon<V> b) {
293 return b.Multiply(a);
294}
295
296template <typename V>
297 requires std::is_scalar_v<V>
298ace Argon<V> operator/(const V a, const Argon<V> b) {
299 return Argon<V>{a}.Divide(b);
300}
301
302namespace std {
303
304template <typename T>
305struct tuple_size<Argon<T>> {
306 static constexpr size_t value = Argon<T>::lanes;
307};
308
309template <size_t Index, typename T>
310struct tuple_element<Index, Argon<T>> {
311 static_assert(Index < Argon<T>::lanes);
313};
314} // namespace std
315
316#undef ace
317#undef simd
Provides utility templates and concepts for type traits and compile-time iteration.
Definition argon_half.hpp:11
Definition argon_full.hpp:24
Represents a single lane of a SIMD vector, where the lane's index is known at compile time.
Definition lane.hpp:44
Represents a single lane of a SIMD vector.
Definition lane.hpp:102
Represents a SIMD vector with various operations.
Definition vector.hpp:50
constexpr simd::Vec128_t< ScalarType > vec() const
Definition vector.hpp:268
ace argon_type Multiply(argon_type b) const
Multiply two vectors.
Definition vector.hpp:411
static ace argon_type Load(const scalar_type *ptr)
Definition vector.hpp:788
ace argon_type Divide(argon_type b) const
Divide two vectors.
Definition vector.hpp:604
ace std::array< scalar_type, lanes > to_array()
Definition vector.hpp:275
ace argon_type Add(argon_type b) const
Add two vectors.
Definition vector.hpp:359
ace argon_type Subtract(argon_type b) const
Subtract two vectors.
Definition vector.hpp:381
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
constexpr bool has_smaller_v
Helper template to determine if a type has a smaller corresponding type.
Definition helpers.hpp:18
Lane deconstruction feature.
Definition argon_full.hpp:302