native 0.0.1
Vectors, masks and wide register packs for C++26
Loading...
Searching...
No Matches
native.arm.neon.ccm
1// SPDX-License-Identifier: BSD-2-Clause OR Apache-2.0
2module;
3#include "native/isa_import.h"
4#include <bit>
5#include "native/arm/neon.h"
6#include "native/arm/neon_constant.h"
7export module native.arm.neon;
8export import native.arm.features;
9export import native.simd;
10#if NATIVE_HOST_NEON || defined(NATIVE_DOXYGEN)
11namespace native::detail::arm_neon_bits {
12 template<class V, class F> consteval V unary(V input, F operation) noexcept {
13 auto values = arm_constant::lanes(input);
14 for (auto &value : values)
15 value = operation(value);
16 return arm_constant::pack<V>(values);
17 }
18
19 template<unsigned Bits, class V> consteval V reverse(V input) noexcept {
20 auto source = arm_constant::lanes(input);
21 auto result = source;
22 constexpr unsigned group = Bits / (8 * sizeof(typename V::value_type));
23 for (unsigned i = 0; i < V::lanes; ++i)
24 result[i] = source[i ^ (group - 1)];
25 return arm_constant::pack<V>(result);
26 }
27}
28
29export namespace native {
37
39 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
40 requires(Arch.has(arm_feature::neon) &&
41 std::is_signed_v<T> && (sizeof(T) <= 8) &&
42 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
43 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
44 sqadd(simd<T, N, Arch> a, simd<T, N, Arch> b) noexcept {
45 if consteval {
46 return detail::arm_neon_constant::binary(
47 a, b, [](auto x, auto y) { return detail::arm_neon_constant::add(x, y); });
48 } else {
49 if constexpr (sizeof(T) == 1 && N == 8)
50 return detail::arm_neon::from_register<simd<T, N, Arch>>(
51 detail::arm_neon::sqadd(detail::arm_neon::to_register<int8x8_t>(a),
52 detail::arm_neon::to_register<int8x8_t>(b)));
53 else if constexpr (sizeof(T) == 1 && N == 16)
54 return detail::arm_neon::from_register<simd<T, N, Arch>>(
55 detail::arm_neon::sqadd(detail::arm_neon::to_register<int8x16_t>(a),
56 detail::arm_neon::to_register<int8x16_t>(b)));
57 else if constexpr (sizeof(T) == 2 && N == 4)
58 return detail::arm_neon::from_register<simd<T, N, Arch>>(
59 detail::arm_neon::sqadd(detail::arm_neon::to_register<int16x4_t>(a),
60 detail::arm_neon::to_register<int16x4_t>(b)));
61 else if constexpr (sizeof(T) == 2 && N == 8)
62 return detail::arm_neon::from_register<simd<T, N, Arch>>(
63 detail::arm_neon::sqadd(detail::arm_neon::to_register<int16x8_t>(a),
64 detail::arm_neon::to_register<int16x8_t>(b)));
65 else if constexpr (sizeof(T) == 4 && N == 2)
66 return detail::arm_neon::from_register<simd<T, N, Arch>>(
67 detail::arm_neon::sqadd(detail::arm_neon::to_register<int32x2_t>(a),
68 detail::arm_neon::to_register<int32x2_t>(b)));
69 else if constexpr (sizeof(T) == 4 && N == 4)
70 return detail::arm_neon::from_register<simd<T, N, Arch>>(
71 detail::arm_neon::sqadd(detail::arm_neon::to_register<int32x4_t>(a),
72 detail::arm_neon::to_register<int32x4_t>(b)));
73 else if constexpr (sizeof(T) == 8 && N == 1)
74 return detail::arm_neon::from_register<simd<T, N, Arch>>(
75 detail::arm_neon::sqadd(detail::arm_neon::to_register<int64x1_t>(a),
76 detail::arm_neon::to_register<int64x1_t>(b)));
77 else if constexpr (sizeof(T) == 8 && N == 2)
78 return detail::arm_neon::from_register<simd<T, N, Arch>>(
79 detail::arm_neon::sqadd(detail::arm_neon::to_register<int64x2_t>(a),
80 detail::arm_neon::to_register<int64x2_t>(b)));
81 }
82 }
83
85 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
86 requires(!Arch.has(arm_feature::neon) &&
87 std::is_signed_v<T> && (sizeof(T) <= 8) &&
88 (sizeof(T) * N == 8 || sizeof(T) * N == 16) && requires { sizeof(simd<T, N, Arch>); })
90 simd<T, N, Arch> b) noexcept {
91 return detail::arm_neon_constant::binary(
92 a, b, [](auto x, auto y) { return detail::arm_neon_constant::add(x, y); });
93 }
94
96 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
97 requires(Arch.has(arm_feature::neon) &&
98 std::is_unsigned_v<T> && (sizeof(T) <= 8) &&
99 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
100 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
101 uqadd(simd<T, N, Arch> a, simd<T, N, Arch> b) noexcept {
102 if consteval {
103 return detail::arm_neon_constant::binary(
104 a, b, [](auto x, auto y) { return detail::arm_neon_constant::add(x, y); });
105 } else {
106 if constexpr (sizeof(T) == 1 && N == 8)
107 return detail::arm_neon::from_register<simd<T, N, Arch>>(
108 detail::arm_neon::uqadd(detail::arm_neon::to_register<uint8x8_t>(a),
109 detail::arm_neon::to_register<uint8x8_t>(b)));
110 else if constexpr (sizeof(T) == 1 && N == 16)
111 return detail::arm_neon::from_register<simd<T, N, Arch>>(
112 detail::arm_neon::uqadd(detail::arm_neon::to_register<uint8x16_t>(a),
113 detail::arm_neon::to_register<uint8x16_t>(b)));
114 else if constexpr (sizeof(T) == 2 && N == 4)
115 return detail::arm_neon::from_register<simd<T, N, Arch>>(
116 detail::arm_neon::uqadd(detail::arm_neon::to_register<uint16x4_t>(a),
117 detail::arm_neon::to_register<uint16x4_t>(b)));
118 else if constexpr (sizeof(T) == 2 && N == 8)
119 return detail::arm_neon::from_register<simd<T, N, Arch>>(
120 detail::arm_neon::uqadd(detail::arm_neon::to_register<uint16x8_t>(a),
121 detail::arm_neon::to_register<uint16x8_t>(b)));
122 else if constexpr (sizeof(T) == 4 && N == 2)
123 return detail::arm_neon::from_register<simd<T, N, Arch>>(
124 detail::arm_neon::uqadd(detail::arm_neon::to_register<uint32x2_t>(a),
125 detail::arm_neon::to_register<uint32x2_t>(b)));
126 else if constexpr (sizeof(T) == 4 && N == 4)
127 return detail::arm_neon::from_register<simd<T, N, Arch>>(
128 detail::arm_neon::uqadd(detail::arm_neon::to_register<uint32x4_t>(a),
129 detail::arm_neon::to_register<uint32x4_t>(b)));
130 else if constexpr (sizeof(T) == 8 && N == 1)
131 return detail::arm_neon::from_register<simd<T, N, Arch>>(
132 detail::arm_neon::uqadd(detail::arm_neon::to_register<uint64x1_t>(a),
133 detail::arm_neon::to_register<uint64x1_t>(b)));
134 else if constexpr (sizeof(T) == 8 && N == 2)
135 return detail::arm_neon::from_register<simd<T, N, Arch>>(
136 detail::arm_neon::uqadd(detail::arm_neon::to_register<uint64x2_t>(a),
137 detail::arm_neon::to_register<uint64x2_t>(b)));
138 }
139 }
140
142 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
143 requires(!Arch.has(arm_feature::neon) &&
144 std::is_unsigned_v<T> && (sizeof(T) <= 8) &&
145 (sizeof(T) * N == 8 || sizeof(T) * N == 16) && requires { sizeof(simd<T, N, Arch>); })
147 simd<T, N, Arch> b) noexcept {
148 return detail::arm_neon_constant::binary(
149 a, b, [](auto x, auto y) { return detail::arm_neon_constant::add(x, y); });
150 }
151
153 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
154 requires(Arch.has(arm_feature::neon) &&
155 std::is_signed_v<T> && (sizeof(T) <= 8) &&
156 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
157 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
158 sqsub(simd<T, N, Arch> a, simd<T, N, Arch> b) noexcept {
159 if consteval {
160 return detail::arm_neon_constant::binary(
161 a, b, [](auto x, auto y) { return detail::arm_neon_constant::sub(x, y); });
162 } else {
163 if constexpr (sizeof(T) == 1 && N == 8)
164 return detail::arm_neon::from_register<simd<T, N, Arch>>(
165 detail::arm_neon::sqsub(detail::arm_neon::to_register<int8x8_t>(a),
166 detail::arm_neon::to_register<int8x8_t>(b)));
167 else if constexpr (sizeof(T) == 1 && N == 16)
168 return detail::arm_neon::from_register<simd<T, N, Arch>>(
169 detail::arm_neon::sqsub(detail::arm_neon::to_register<int8x16_t>(a),
170 detail::arm_neon::to_register<int8x16_t>(b)));
171 else if constexpr (sizeof(T) == 2 && N == 4)
172 return detail::arm_neon::from_register<simd<T, N, Arch>>(
173 detail::arm_neon::sqsub(detail::arm_neon::to_register<int16x4_t>(a),
174 detail::arm_neon::to_register<int16x4_t>(b)));
175 else if constexpr (sizeof(T) == 2 && N == 8)
176 return detail::arm_neon::from_register<simd<T, N, Arch>>(
177 detail::arm_neon::sqsub(detail::arm_neon::to_register<int16x8_t>(a),
178 detail::arm_neon::to_register<int16x8_t>(b)));
179 else if constexpr (sizeof(T) == 4 && N == 2)
180 return detail::arm_neon::from_register<simd<T, N, Arch>>(
181 detail::arm_neon::sqsub(detail::arm_neon::to_register<int32x2_t>(a),
182 detail::arm_neon::to_register<int32x2_t>(b)));
183 else if constexpr (sizeof(T) == 4 && N == 4)
184 return detail::arm_neon::from_register<simd<T, N, Arch>>(
185 detail::arm_neon::sqsub(detail::arm_neon::to_register<int32x4_t>(a),
186 detail::arm_neon::to_register<int32x4_t>(b)));
187 else if constexpr (sizeof(T) == 8 && N == 1)
188 return detail::arm_neon::from_register<simd<T, N, Arch>>(
189 detail::arm_neon::sqsub(detail::arm_neon::to_register<int64x1_t>(a),
190 detail::arm_neon::to_register<int64x1_t>(b)));
191 else if constexpr (sizeof(T) == 8 && N == 2)
192 return detail::arm_neon::from_register<simd<T, N, Arch>>(
193 detail::arm_neon::sqsub(detail::arm_neon::to_register<int64x2_t>(a),
194 detail::arm_neon::to_register<int64x2_t>(b)));
195 }
196 }
197
199 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
200 requires(!Arch.has(arm_feature::neon) &&
201 std::is_signed_v<T> && (sizeof(T) <= 8) &&
202 (sizeof(T) * N == 8 || sizeof(T) * N == 16) && requires { sizeof(simd<T, N, Arch>); })
204 simd<T, N, Arch> b) noexcept {
205 return detail::arm_neon_constant::binary(
206 a, b, [](auto x, auto y) { return detail::arm_neon_constant::sub(x, y); });
207 }
208
210 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
211 requires(Arch.has(arm_feature::neon) &&
212 std::is_unsigned_v<T> && (sizeof(T) <= 8) &&
213 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
214 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
215 uqsub(simd<T, N, Arch> a, simd<T, N, Arch> b) noexcept {
216 if consteval {
217 return detail::arm_neon_constant::binary(
218 a, b, [](auto x, auto y) { return detail::arm_neon_constant::sub(x, y); });
219 } else {
220 if constexpr (sizeof(T) == 1 && N == 8)
221 return detail::arm_neon::from_register<simd<T, N, Arch>>(
222 detail::arm_neon::uqsub(detail::arm_neon::to_register<uint8x8_t>(a),
223 detail::arm_neon::to_register<uint8x8_t>(b)));
224 else if constexpr (sizeof(T) == 1 && N == 16)
225 return detail::arm_neon::from_register<simd<T, N, Arch>>(
226 detail::arm_neon::uqsub(detail::arm_neon::to_register<uint8x16_t>(a),
227 detail::arm_neon::to_register<uint8x16_t>(b)));
228 else if constexpr (sizeof(T) == 2 && N == 4)
229 return detail::arm_neon::from_register<simd<T, N, Arch>>(
230 detail::arm_neon::uqsub(detail::arm_neon::to_register<uint16x4_t>(a),
231 detail::arm_neon::to_register<uint16x4_t>(b)));
232 else if constexpr (sizeof(T) == 2 && N == 8)
233 return detail::arm_neon::from_register<simd<T, N, Arch>>(
234 detail::arm_neon::uqsub(detail::arm_neon::to_register<uint16x8_t>(a),
235 detail::arm_neon::to_register<uint16x8_t>(b)));
236 else if constexpr (sizeof(T) == 4 && N == 2)
237 return detail::arm_neon::from_register<simd<T, N, Arch>>(
238 detail::arm_neon::uqsub(detail::arm_neon::to_register<uint32x2_t>(a),
239 detail::arm_neon::to_register<uint32x2_t>(b)));
240 else if constexpr (sizeof(T) == 4 && N == 4)
241 return detail::arm_neon::from_register<simd<T, N, Arch>>(
242 detail::arm_neon::uqsub(detail::arm_neon::to_register<uint32x4_t>(a),
243 detail::arm_neon::to_register<uint32x4_t>(b)));
244 else if constexpr (sizeof(T) == 8 && N == 1)
245 return detail::arm_neon::from_register<simd<T, N, Arch>>(
246 detail::arm_neon::uqsub(detail::arm_neon::to_register<uint64x1_t>(a),
247 detail::arm_neon::to_register<uint64x1_t>(b)));
248 else if constexpr (sizeof(T) == 8 && N == 2)
249 return detail::arm_neon::from_register<simd<T, N, Arch>>(
250 detail::arm_neon::uqsub(detail::arm_neon::to_register<uint64x2_t>(a),
251 detail::arm_neon::to_register<uint64x2_t>(b)));
252 }
253 }
254
256 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
257 requires(!Arch.has(arm_feature::neon) &&
258 std::is_unsigned_v<T> && (sizeof(T) <= 8) &&
259 (sizeof(T) * N == 8 || sizeof(T) * N == 16) && requires { sizeof(simd<T, N, Arch>); })
261 simd<T, N, Arch> b) noexcept {
262 return detail::arm_neon_constant::binary(
263 a, b, [](auto x, auto y) { return detail::arm_neon_constant::sub(x, y); });
264 }
265
267 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
268 requires(Arch.has(arm_feature::neon) && std::is_signed_v<T> &&
269 (sizeof(T) == 2 || sizeof(T) == 4) && (sizeof(T) * N == 8 || sizeof(T) * N == 16))
270 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
271 sqdmulh(simd<T, N, Arch> a, simd<T, N, Arch> b) noexcept {
272 if consteval {
273 return detail::arm_neon_constant::binary(a, b, [](auto x, auto y) {
274 return detail::arm_neon_constant::multiply_high<false>(x, y);
275 });
276 } else {
277 if constexpr (sizeof(T) == 2 && N == 4)
278 return detail::arm_neon::from_register<simd<T, N, Arch>>(
279 detail::arm_neon::sqdmulh(detail::arm_neon::to_register<int16x4_t>(a),
280 detail::arm_neon::to_register<int16x4_t>(b)));
281 else if constexpr (sizeof(T) == 2 && N == 8)
282 return detail::arm_neon::from_register<simd<T, N, Arch>>(
283 detail::arm_neon::sqdmulh(detail::arm_neon::to_register<int16x8_t>(a),
284 detail::arm_neon::to_register<int16x8_t>(b)));
285 else if constexpr (sizeof(T) == 4 && N == 2)
286 return detail::arm_neon::from_register<simd<T, N, Arch>>(
287 detail::arm_neon::sqdmulh(detail::arm_neon::to_register<int32x2_t>(a),
288 detail::arm_neon::to_register<int32x2_t>(b)));
289 else if constexpr (sizeof(T) == 4 && N == 4)
290 return detail::arm_neon::from_register<simd<T, N, Arch>>(
291 detail::arm_neon::sqdmulh(detail::arm_neon::to_register<int32x4_t>(a),
292 detail::arm_neon::to_register<int32x4_t>(b)));
293 }
294 }
295
297 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
298 requires(!Arch.has(arm_feature::neon) && std::is_signed_v<T> &&
299 (sizeof(T) == 2 || sizeof(T) == 4) && (sizeof(T) * N == 8 || sizeof(T) * N == 16) &&
300 requires { sizeof(simd<T, N, Arch>); })
302 simd<T, N, Arch> b) noexcept {
303 return detail::arm_neon_constant::binary(
304 a, b, [](auto x, auto y) { return detail::arm_neon_constant::multiply_high<false>(x, y); });
305 }
306
308 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
309 requires(Arch.has(arm_feature::neon) && std::is_signed_v<T> &&
310 (sizeof(T) == 2 || sizeof(T) == 4) && (sizeof(T) * N == 8 || sizeof(T) * N == 16))
311 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
312 sqrdmulh(simd<T, N, Arch> a, simd<T, N, Arch> b) noexcept {
313 if consteval {
314 return detail::arm_neon_constant::binary(a, b, [](auto x, auto y) {
315 return detail::arm_neon_constant::multiply_high<true>(x, y);
316 });
317 } else {
318 if constexpr (sizeof(T) == 2 && N == 4)
319 return detail::arm_neon::from_register<simd<T, N, Arch>>(
320 detail::arm_neon::sqrdmulh(detail::arm_neon::to_register<int16x4_t>(a),
321 detail::arm_neon::to_register<int16x4_t>(b)));
322 else if constexpr (sizeof(T) == 2 && N == 8)
323 return detail::arm_neon::from_register<simd<T, N, Arch>>(
324 detail::arm_neon::sqrdmulh(detail::arm_neon::to_register<int16x8_t>(a),
325 detail::arm_neon::to_register<int16x8_t>(b)));
326 else if constexpr (sizeof(T) == 4 && N == 2)
327 return detail::arm_neon::from_register<simd<T, N, Arch>>(
328 detail::arm_neon::sqrdmulh(detail::arm_neon::to_register<int32x2_t>(a),
329 detail::arm_neon::to_register<int32x2_t>(b)));
330 else if constexpr (sizeof(T) == 4 && N == 4)
331 return detail::arm_neon::from_register<simd<T, N, Arch>>(
332 detail::arm_neon::sqrdmulh(detail::arm_neon::to_register<int32x4_t>(a),
333 detail::arm_neon::to_register<int32x4_t>(b)));
334 }
335 }
336
338 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
339 requires(!Arch.has(arm_feature::neon) && std::is_signed_v<T> &&
340 (sizeof(T) == 2 || sizeof(T) == 4) && (sizeof(T) * N == 8 || sizeof(T) * N == 16) &&
341 requires { sizeof(simd<T, N, Arch>); })
343 simd<T, N, Arch> b) noexcept {
344 return detail::arm_neon_constant::binary(
345 a, b, [](auto x, auto y) { return detail::arm_neon_constant::multiply_high<true>(x, y); });
346 }
347
349 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
350 requires(Arch.has(arm_feature::neon) &&
351 std::is_signed_v<T> && (sizeof(T) <= 8) &&
352 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
353 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
354 sshl(simd<T, N, Arch> a, simd<std::make_signed_t<T>, N, Arch> b) noexcept {
355 if consteval {
356 return detail::arm_neon_constant::binary(a, b, [](auto x, auto y) {
357 return detail::arm_neon_constant::shift<false, false>(x, y);
358 });
359 } else {
360 if constexpr (sizeof(T) == 1 && N == 8)
361 return detail::arm_neon::from_register<simd<T, N, Arch>>(
362 detail::arm_neon::sshl(detail::arm_neon::to_register<int8x8_t>(a),
363 detail::arm_neon::to_register<int8x8_t>(b)));
364 else if constexpr (sizeof(T) == 1 && N == 16)
365 return detail::arm_neon::from_register<simd<T, N, Arch>>(
366 detail::arm_neon::sshl(detail::arm_neon::to_register<int8x16_t>(a),
367 detail::arm_neon::to_register<int8x16_t>(b)));
368 else if constexpr (sizeof(T) == 2 && N == 4)
369 return detail::arm_neon::from_register<simd<T, N, Arch>>(
370 detail::arm_neon::sshl(detail::arm_neon::to_register<int16x4_t>(a),
371 detail::arm_neon::to_register<int16x4_t>(b)));
372 else if constexpr (sizeof(T) == 2 && N == 8)
373 return detail::arm_neon::from_register<simd<T, N, Arch>>(
374 detail::arm_neon::sshl(detail::arm_neon::to_register<int16x8_t>(a),
375 detail::arm_neon::to_register<int16x8_t>(b)));
376 else if constexpr (sizeof(T) == 4 && N == 2)
377 return detail::arm_neon::from_register<simd<T, N, Arch>>(
378 detail::arm_neon::sshl(detail::arm_neon::to_register<int32x2_t>(a),
379 detail::arm_neon::to_register<int32x2_t>(b)));
380 else if constexpr (sizeof(T) == 4 && N == 4)
381 return detail::arm_neon::from_register<simd<T, N, Arch>>(
382 detail::arm_neon::sshl(detail::arm_neon::to_register<int32x4_t>(a),
383 detail::arm_neon::to_register<int32x4_t>(b)));
384 else if constexpr (sizeof(T) == 8 && N == 1)
385 return detail::arm_neon::from_register<simd<T, N, Arch>>(
386 detail::arm_neon::sshl(detail::arm_neon::to_register<int64x1_t>(a),
387 detail::arm_neon::to_register<int64x1_t>(b)));
388 else if constexpr (sizeof(T) == 8 && N == 2)
389 return detail::arm_neon::from_register<simd<T, N, Arch>>(
390 detail::arm_neon::sshl(detail::arm_neon::to_register<int64x2_t>(a),
391 detail::arm_neon::to_register<int64x2_t>(b)));
392 }
393 }
394
396 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
397 requires(!Arch.has(arm_feature::neon) &&
398 std::is_signed_v<T> && (sizeof(T) <= 8) &&
399 (sizeof(T) * N == 8 || sizeof(T) * N == 16) && requires { sizeof(simd<T, N, Arch>); })
401 sshl(simd<T, N, Arch> a, simd<std::make_signed_t<T>, N, Arch> b) noexcept {
402 return detail::arm_neon_constant::binary(
403 a, b, [](auto x, auto y) { return detail::arm_neon_constant::shift<false, false>(x, y); });
404 }
405
407 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
408 requires(Arch.has(arm_feature::neon) &&
409 std::is_signed_v<T> && (sizeof(T) <= 8) &&
410 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
411 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
412 srshl(simd<T, N, Arch> a, simd<std::make_signed_t<T>, N, Arch> b) noexcept {
413 if consteval {
414 return detail::arm_neon_constant::binary(
415 a, b, [](auto x, auto y) { return detail::arm_neon_constant::shift<true, false>(x, y); });
416 } else {
417 if constexpr (sizeof(T) == 1 && N == 8)
418 return detail::arm_neon::from_register<simd<T, N, Arch>>(
419 detail::arm_neon::srshl(detail::arm_neon::to_register<int8x8_t>(a),
420 detail::arm_neon::to_register<int8x8_t>(b)));
421 else if constexpr (sizeof(T) == 1 && N == 16)
422 return detail::arm_neon::from_register<simd<T, N, Arch>>(
423 detail::arm_neon::srshl(detail::arm_neon::to_register<int8x16_t>(a),
424 detail::arm_neon::to_register<int8x16_t>(b)));
425 else if constexpr (sizeof(T) == 2 && N == 4)
426 return detail::arm_neon::from_register<simd<T, N, Arch>>(
427 detail::arm_neon::srshl(detail::arm_neon::to_register<int16x4_t>(a),
428 detail::arm_neon::to_register<int16x4_t>(b)));
429 else if constexpr (sizeof(T) == 2 && N == 8)
430 return detail::arm_neon::from_register<simd<T, N, Arch>>(
431 detail::arm_neon::srshl(detail::arm_neon::to_register<int16x8_t>(a),
432 detail::arm_neon::to_register<int16x8_t>(b)));
433 else if constexpr (sizeof(T) == 4 && N == 2)
434 return detail::arm_neon::from_register<simd<T, N, Arch>>(
435 detail::arm_neon::srshl(detail::arm_neon::to_register<int32x2_t>(a),
436 detail::arm_neon::to_register<int32x2_t>(b)));
437 else if constexpr (sizeof(T) == 4 && N == 4)
438 return detail::arm_neon::from_register<simd<T, N, Arch>>(
439 detail::arm_neon::srshl(detail::arm_neon::to_register<int32x4_t>(a),
440 detail::arm_neon::to_register<int32x4_t>(b)));
441 else if constexpr (sizeof(T) == 8 && N == 1)
442 return detail::arm_neon::from_register<simd<T, N, Arch>>(
443 detail::arm_neon::srshl(detail::arm_neon::to_register<int64x1_t>(a),
444 detail::arm_neon::to_register<int64x1_t>(b)));
445 else if constexpr (sizeof(T) == 8 && N == 2)
446 return detail::arm_neon::from_register<simd<T, N, Arch>>(
447 detail::arm_neon::srshl(detail::arm_neon::to_register<int64x2_t>(a),
448 detail::arm_neon::to_register<int64x2_t>(b)));
449 }
450 }
451
453 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
454 requires(!Arch.has(arm_feature::neon) &&
455 std::is_signed_v<T> && (sizeof(T) <= 8) &&
456 (sizeof(T) * N == 8 || sizeof(T) * N == 16) && requires { sizeof(simd<T, N, Arch>); })
458 srshl(simd<T, N, Arch> a, simd<std::make_signed_t<T>, N, Arch> b) noexcept {
459 return detail::arm_neon_constant::binary(
460 a, b, [](auto x, auto y) { return detail::arm_neon_constant::shift<true, false>(x, y); });
461 }
462
465 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
466 requires(Arch.has(arm_feature::neon) &&
467 std::is_signed_v<T> && (sizeof(T) <= 8) &&
468 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
469 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
470 sqshl(simd<T, N, Arch> a, simd<std::make_signed_t<T>, N, Arch> b) noexcept {
471 if consteval {
472 return detail::arm_neon_constant::binary(
473 a, b, [](auto x, auto y) { return detail::arm_neon_constant::shift<false, true>(x, y); });
474 } else {
475 if constexpr (sizeof(T) == 1 && N == 8)
476 return detail::arm_neon::from_register<simd<T, N, Arch>>(
477 detail::arm_neon::sqshl(detail::arm_neon::to_register<int8x8_t>(a),
478 detail::arm_neon::to_register<int8x8_t>(b)));
479 else if constexpr (sizeof(T) == 1 && N == 16)
480 return detail::arm_neon::from_register<simd<T, N, Arch>>(
481 detail::arm_neon::sqshl(detail::arm_neon::to_register<int8x16_t>(a),
482 detail::arm_neon::to_register<int8x16_t>(b)));
483 else if constexpr (sizeof(T) == 2 && N == 4)
484 return detail::arm_neon::from_register<simd<T, N, Arch>>(
485 detail::arm_neon::sqshl(detail::arm_neon::to_register<int16x4_t>(a),
486 detail::arm_neon::to_register<int16x4_t>(b)));
487 else if constexpr (sizeof(T) == 2 && N == 8)
488 return detail::arm_neon::from_register<simd<T, N, Arch>>(
489 detail::arm_neon::sqshl(detail::arm_neon::to_register<int16x8_t>(a),
490 detail::arm_neon::to_register<int16x8_t>(b)));
491 else if constexpr (sizeof(T) == 4 && N == 2)
492 return detail::arm_neon::from_register<simd<T, N, Arch>>(
493 detail::arm_neon::sqshl(detail::arm_neon::to_register<int32x2_t>(a),
494 detail::arm_neon::to_register<int32x2_t>(b)));
495 else if constexpr (sizeof(T) == 4 && N == 4)
496 return detail::arm_neon::from_register<simd<T, N, Arch>>(
497 detail::arm_neon::sqshl(detail::arm_neon::to_register<int32x4_t>(a),
498 detail::arm_neon::to_register<int32x4_t>(b)));
499 else if constexpr (sizeof(T) == 8 && N == 1)
500 return detail::arm_neon::from_register<simd<T, N, Arch>>(
501 detail::arm_neon::sqshl(detail::arm_neon::to_register<int64x1_t>(a),
502 detail::arm_neon::to_register<int64x1_t>(b)));
503 else if constexpr (sizeof(T) == 8 && N == 2)
504 return detail::arm_neon::from_register<simd<T, N, Arch>>(
505 detail::arm_neon::sqshl(detail::arm_neon::to_register<int64x2_t>(a),
506 detail::arm_neon::to_register<int64x2_t>(b)));
507 }
508 }
509
511 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
512 requires(!Arch.has(arm_feature::neon) &&
513 std::is_signed_v<T> && (sizeof(T) <= 8) &&
514 (sizeof(T) * N == 8 || sizeof(T) * N == 16) && requires { sizeof(simd<T, N, Arch>); })
516 sqshl(simd<T, N, Arch> a, simd<std::make_signed_t<T>, N, Arch> b) noexcept {
517 return detail::arm_neon_constant::binary(
518 a, b, [](auto x, auto y) { return detail::arm_neon_constant::shift<false, true>(x, y); });
519 }
520
523 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
524 requires(Arch.has(arm_feature::neon) &&
525 std::is_signed_v<T> && (sizeof(T) <= 8) &&
526 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
527 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
528 sqrshl(simd<T, N, Arch> a, simd<std::make_signed_t<T>, N, Arch> b) noexcept {
529 if consteval {
530 return detail::arm_neon_constant::binary(
531 a, b, [](auto x, auto y) { return detail::arm_neon_constant::shift<true, true>(x, y); });
532 } else {
533 if constexpr (sizeof(T) == 1 && N == 8)
534 return detail::arm_neon::from_register<simd<T, N, Arch>>(
535 detail::arm_neon::sqrshl(detail::arm_neon::to_register<int8x8_t>(a),
536 detail::arm_neon::to_register<int8x8_t>(b)));
537 else if constexpr (sizeof(T) == 1 && N == 16)
538 return detail::arm_neon::from_register<simd<T, N, Arch>>(
539 detail::arm_neon::sqrshl(detail::arm_neon::to_register<int8x16_t>(a),
540 detail::arm_neon::to_register<int8x16_t>(b)));
541 else if constexpr (sizeof(T) == 2 && N == 4)
542 return detail::arm_neon::from_register<simd<T, N, Arch>>(
543 detail::arm_neon::sqrshl(detail::arm_neon::to_register<int16x4_t>(a),
544 detail::arm_neon::to_register<int16x4_t>(b)));
545 else if constexpr (sizeof(T) == 2 && N == 8)
546 return detail::arm_neon::from_register<simd<T, N, Arch>>(
547 detail::arm_neon::sqrshl(detail::arm_neon::to_register<int16x8_t>(a),
548 detail::arm_neon::to_register<int16x8_t>(b)));
549 else if constexpr (sizeof(T) == 4 && N == 2)
550 return detail::arm_neon::from_register<simd<T, N, Arch>>(
551 detail::arm_neon::sqrshl(detail::arm_neon::to_register<int32x2_t>(a),
552 detail::arm_neon::to_register<int32x2_t>(b)));
553 else if constexpr (sizeof(T) == 4 && N == 4)
554 return detail::arm_neon::from_register<simd<T, N, Arch>>(
555 detail::arm_neon::sqrshl(detail::arm_neon::to_register<int32x4_t>(a),
556 detail::arm_neon::to_register<int32x4_t>(b)));
557 else if constexpr (sizeof(T) == 8 && N == 1)
558 return detail::arm_neon::from_register<simd<T, N, Arch>>(
559 detail::arm_neon::sqrshl(detail::arm_neon::to_register<int64x1_t>(a),
560 detail::arm_neon::to_register<int64x1_t>(b)));
561 else if constexpr (sizeof(T) == 8 && N == 2)
562 return detail::arm_neon::from_register<simd<T, N, Arch>>(
563 detail::arm_neon::sqrshl(detail::arm_neon::to_register<int64x2_t>(a),
564 detail::arm_neon::to_register<int64x2_t>(b)));
565 }
566 }
567
569 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
570 requires(!Arch.has(arm_feature::neon) &&
571 std::is_signed_v<T> && (sizeof(T) <= 8) &&
572 (sizeof(T) * N == 8 || sizeof(T) * N == 16) && requires { sizeof(simd<T, N, Arch>); })
574 sqrshl(simd<T, N, Arch> a, simd<std::make_signed_t<T>, N, Arch> b) noexcept {
575 return detail::arm_neon_constant::binary(
576 a, b, [](auto x, auto y) { return detail::arm_neon_constant::shift<true, true>(x, y); });
577 }
578
580 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
581 requires(Arch.has(arm_feature::neon) &&
582 std::is_unsigned_v<T> && (sizeof(T) <= 8) &&
583 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
584 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
585 ushl(simd<T, N, Arch> a, simd<std::make_signed_t<T>, N, Arch> b) noexcept {
586 if consteval {
587 return detail::arm_neon_constant::binary(a, b, [](auto x, auto y) {
588 return detail::arm_neon_constant::shift<false, false>(x, y);
589 });
590 } else {
591 if constexpr (sizeof(T) == 1 && N == 8)
592 return detail::arm_neon::from_register<simd<T, N, Arch>>(
593 detail::arm_neon::ushl(detail::arm_neon::to_register<uint8x8_t>(a),
594 detail::arm_neon::to_register<int8x8_t>(b)));
595 else if constexpr (sizeof(T) == 1 && N == 16)
596 return detail::arm_neon::from_register<simd<T, N, Arch>>(
597 detail::arm_neon::ushl(detail::arm_neon::to_register<uint8x16_t>(a),
598 detail::arm_neon::to_register<int8x16_t>(b)));
599 else if constexpr (sizeof(T) == 2 && N == 4)
600 return detail::arm_neon::from_register<simd<T, N, Arch>>(
601 detail::arm_neon::ushl(detail::arm_neon::to_register<uint16x4_t>(a),
602 detail::arm_neon::to_register<int16x4_t>(b)));
603 else if constexpr (sizeof(T) == 2 && N == 8)
604 return detail::arm_neon::from_register<simd<T, N, Arch>>(
605 detail::arm_neon::ushl(detail::arm_neon::to_register<uint16x8_t>(a),
606 detail::arm_neon::to_register<int16x8_t>(b)));
607 else if constexpr (sizeof(T) == 4 && N == 2)
608 return detail::arm_neon::from_register<simd<T, N, Arch>>(
609 detail::arm_neon::ushl(detail::arm_neon::to_register<uint32x2_t>(a),
610 detail::arm_neon::to_register<int32x2_t>(b)));
611 else if constexpr (sizeof(T) == 4 && N == 4)
612 return detail::arm_neon::from_register<simd<T, N, Arch>>(
613 detail::arm_neon::ushl(detail::arm_neon::to_register<uint32x4_t>(a),
614 detail::arm_neon::to_register<int32x4_t>(b)));
615 else if constexpr (sizeof(T) == 8 && N == 1)
616 return detail::arm_neon::from_register<simd<T, N, Arch>>(
617 detail::arm_neon::ushl(detail::arm_neon::to_register<uint64x1_t>(a),
618 detail::arm_neon::to_register<int64x1_t>(b)));
619 else if constexpr (sizeof(T) == 8 && N == 2)
620 return detail::arm_neon::from_register<simd<T, N, Arch>>(
621 detail::arm_neon::ushl(detail::arm_neon::to_register<uint64x2_t>(a),
622 detail::arm_neon::to_register<int64x2_t>(b)));
623 }
624 }
625
627 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
628 requires(!Arch.has(arm_feature::neon) &&
629 std::is_unsigned_v<T> && (sizeof(T) <= 8) &&
630 (sizeof(T) * N == 8 || sizeof(T) * N == 16) && requires { sizeof(simd<T, N, Arch>); })
632 ushl(simd<T, N, Arch> a, simd<std::make_signed_t<T>, N, Arch> b) noexcept {
633 return detail::arm_neon_constant::binary(
634 a, b, [](auto x, auto y) { return detail::arm_neon_constant::shift<false, false>(x, y); });
635 }
636
638 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
639 requires(Arch.has(arm_feature::neon) &&
640 std::is_unsigned_v<T> && (sizeof(T) <= 8) &&
641 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
642 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
643 urshl(simd<T, N, Arch> a, simd<std::make_signed_t<T>, N, Arch> b) noexcept {
644 if consteval {
645 return detail::arm_neon_constant::binary(
646 a, b, [](auto x, auto y) { return detail::arm_neon_constant::shift<true, false>(x, y); });
647 } else {
648 if constexpr (sizeof(T) == 1 && N == 8)
649 return detail::arm_neon::from_register<simd<T, N, Arch>>(
650 detail::arm_neon::urshl(detail::arm_neon::to_register<uint8x8_t>(a),
651 detail::arm_neon::to_register<int8x8_t>(b)));
652 else if constexpr (sizeof(T) == 1 && N == 16)
653 return detail::arm_neon::from_register<simd<T, N, Arch>>(
654 detail::arm_neon::urshl(detail::arm_neon::to_register<uint8x16_t>(a),
655 detail::arm_neon::to_register<int8x16_t>(b)));
656 else if constexpr (sizeof(T) == 2 && N == 4)
657 return detail::arm_neon::from_register<simd<T, N, Arch>>(
658 detail::arm_neon::urshl(detail::arm_neon::to_register<uint16x4_t>(a),
659 detail::arm_neon::to_register<int16x4_t>(b)));
660 else if constexpr (sizeof(T) == 2 && N == 8)
661 return detail::arm_neon::from_register<simd<T, N, Arch>>(
662 detail::arm_neon::urshl(detail::arm_neon::to_register<uint16x8_t>(a),
663 detail::arm_neon::to_register<int16x8_t>(b)));
664 else if constexpr (sizeof(T) == 4 && N == 2)
665 return detail::arm_neon::from_register<simd<T, N, Arch>>(
666 detail::arm_neon::urshl(detail::arm_neon::to_register<uint32x2_t>(a),
667 detail::arm_neon::to_register<int32x2_t>(b)));
668 else if constexpr (sizeof(T) == 4 && N == 4)
669 return detail::arm_neon::from_register<simd<T, N, Arch>>(
670 detail::arm_neon::urshl(detail::arm_neon::to_register<uint32x4_t>(a),
671 detail::arm_neon::to_register<int32x4_t>(b)));
672 else if constexpr (sizeof(T) == 8 && N == 1)
673 return detail::arm_neon::from_register<simd<T, N, Arch>>(
674 detail::arm_neon::urshl(detail::arm_neon::to_register<uint64x1_t>(a),
675 detail::arm_neon::to_register<int64x1_t>(b)));
676 else if constexpr (sizeof(T) == 8 && N == 2)
677 return detail::arm_neon::from_register<simd<T, N, Arch>>(
678 detail::arm_neon::urshl(detail::arm_neon::to_register<uint64x2_t>(a),
679 detail::arm_neon::to_register<int64x2_t>(b)));
680 }
681 }
682
684 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
685 requires(!Arch.has(arm_feature::neon) &&
686 std::is_unsigned_v<T> && (sizeof(T) <= 8) &&
687 (sizeof(T) * N == 8 || sizeof(T) * N == 16) && requires { sizeof(simd<T, N, Arch>); })
689 urshl(simd<T, N, Arch> a, simd<std::make_signed_t<T>, N, Arch> b) noexcept {
690 return detail::arm_neon_constant::binary(
691 a, b, [](auto x, auto y) { return detail::arm_neon_constant::shift<true, false>(x, y); });
692 }
693
696 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
697 requires(Arch.has(arm_feature::neon) &&
698 std::is_unsigned_v<T> && (sizeof(T) <= 8) &&
699 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
700 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
701 uqshl(simd<T, N, Arch> a, simd<std::make_signed_t<T>, N, Arch> b) noexcept {
702 if consteval {
703 return detail::arm_neon_constant::binary(
704 a, b, [](auto x, auto y) { return detail::arm_neon_constant::shift<false, true>(x, y); });
705 } else {
706 if constexpr (sizeof(T) == 1 && N == 8)
707 return detail::arm_neon::from_register<simd<T, N, Arch>>(
708 detail::arm_neon::uqshl(detail::arm_neon::to_register<uint8x8_t>(a),
709 detail::arm_neon::to_register<int8x8_t>(b)));
710 else if constexpr (sizeof(T) == 1 && N == 16)
711 return detail::arm_neon::from_register<simd<T, N, Arch>>(
712 detail::arm_neon::uqshl(detail::arm_neon::to_register<uint8x16_t>(a),
713 detail::arm_neon::to_register<int8x16_t>(b)));
714 else if constexpr (sizeof(T) == 2 && N == 4)
715 return detail::arm_neon::from_register<simd<T, N, Arch>>(
716 detail::arm_neon::uqshl(detail::arm_neon::to_register<uint16x4_t>(a),
717 detail::arm_neon::to_register<int16x4_t>(b)));
718 else if constexpr (sizeof(T) == 2 && N == 8)
719 return detail::arm_neon::from_register<simd<T, N, Arch>>(
720 detail::arm_neon::uqshl(detail::arm_neon::to_register<uint16x8_t>(a),
721 detail::arm_neon::to_register<int16x8_t>(b)));
722 else if constexpr (sizeof(T) == 4 && N == 2)
723 return detail::arm_neon::from_register<simd<T, N, Arch>>(
724 detail::arm_neon::uqshl(detail::arm_neon::to_register<uint32x2_t>(a),
725 detail::arm_neon::to_register<int32x2_t>(b)));
726 else if constexpr (sizeof(T) == 4 && N == 4)
727 return detail::arm_neon::from_register<simd<T, N, Arch>>(
728 detail::arm_neon::uqshl(detail::arm_neon::to_register<uint32x4_t>(a),
729 detail::arm_neon::to_register<int32x4_t>(b)));
730 else if constexpr (sizeof(T) == 8 && N == 1)
731 return detail::arm_neon::from_register<simd<T, N, Arch>>(
732 detail::arm_neon::uqshl(detail::arm_neon::to_register<uint64x1_t>(a),
733 detail::arm_neon::to_register<int64x1_t>(b)));
734 else if constexpr (sizeof(T) == 8 && N == 2)
735 return detail::arm_neon::from_register<simd<T, N, Arch>>(
736 detail::arm_neon::uqshl(detail::arm_neon::to_register<uint64x2_t>(a),
737 detail::arm_neon::to_register<int64x2_t>(b)));
738 }
739 }
740
742 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
743 requires(!Arch.has(arm_feature::neon) &&
744 std::is_unsigned_v<T> && (sizeof(T) <= 8) &&
745 (sizeof(T) * N == 8 || sizeof(T) * N == 16) && requires { sizeof(simd<T, N, Arch>); })
747 uqshl(simd<T, N, Arch> a, simd<std::make_signed_t<T>, N, Arch> b) noexcept {
748 return detail::arm_neon_constant::binary(
749 a, b, [](auto x, auto y) { return detail::arm_neon_constant::shift<false, true>(x, y); });
750 }
751
754 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
755 requires(Arch.has(arm_feature::neon) &&
756 std::is_unsigned_v<T> && (sizeof(T) <= 8) &&
757 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
758 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
759 uqrshl(simd<T, N, Arch> a, simd<std::make_signed_t<T>, N, Arch> b) noexcept {
760 if consteval {
761 return detail::arm_neon_constant::binary(
762 a, b, [](auto x, auto y) { return detail::arm_neon_constant::shift<true, true>(x, y); });
763 } else {
764 if constexpr (sizeof(T) == 1 && N == 8)
765 return detail::arm_neon::from_register<simd<T, N, Arch>>(
766 detail::arm_neon::uqrshl(detail::arm_neon::to_register<uint8x8_t>(a),
767 detail::arm_neon::to_register<int8x8_t>(b)));
768 else if constexpr (sizeof(T) == 1 && N == 16)
769 return detail::arm_neon::from_register<simd<T, N, Arch>>(
770 detail::arm_neon::uqrshl(detail::arm_neon::to_register<uint8x16_t>(a),
771 detail::arm_neon::to_register<int8x16_t>(b)));
772 else if constexpr (sizeof(T) == 2 && N == 4)
773 return detail::arm_neon::from_register<simd<T, N, Arch>>(
774 detail::arm_neon::uqrshl(detail::arm_neon::to_register<uint16x4_t>(a),
775 detail::arm_neon::to_register<int16x4_t>(b)));
776 else if constexpr (sizeof(T) == 2 && N == 8)
777 return detail::arm_neon::from_register<simd<T, N, Arch>>(
778 detail::arm_neon::uqrshl(detail::arm_neon::to_register<uint16x8_t>(a),
779 detail::arm_neon::to_register<int16x8_t>(b)));
780 else if constexpr (sizeof(T) == 4 && N == 2)
781 return detail::arm_neon::from_register<simd<T, N, Arch>>(
782 detail::arm_neon::uqrshl(detail::arm_neon::to_register<uint32x2_t>(a),
783 detail::arm_neon::to_register<int32x2_t>(b)));
784 else if constexpr (sizeof(T) == 4 && N == 4)
785 return detail::arm_neon::from_register<simd<T, N, Arch>>(
786 detail::arm_neon::uqrshl(detail::arm_neon::to_register<uint32x4_t>(a),
787 detail::arm_neon::to_register<int32x4_t>(b)));
788 else if constexpr (sizeof(T) == 8 && N == 1)
789 return detail::arm_neon::from_register<simd<T, N, Arch>>(
790 detail::arm_neon::uqrshl(detail::arm_neon::to_register<uint64x1_t>(a),
791 detail::arm_neon::to_register<int64x1_t>(b)));
792 else if constexpr (sizeof(T) == 8 && N == 2)
793 return detail::arm_neon::from_register<simd<T, N, Arch>>(
794 detail::arm_neon::uqrshl(detail::arm_neon::to_register<uint64x2_t>(a),
795 detail::arm_neon::to_register<int64x2_t>(b)));
796 }
797 }
798
800 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
801 requires(!Arch.has(arm_feature::neon) &&
802 std::is_unsigned_v<T> && (sizeof(T) <= 8) &&
803 (sizeof(T) * N == 8 || sizeof(T) * N == 16) && requires { sizeof(simd<T, N, Arch>); })
805 uqrshl(simd<T, N, Arch> a, simd<std::make_signed_t<T>, N, Arch> b) noexcept {
806 return detail::arm_neon_constant::binary(
807 a, b, [](auto x, auto y) { return detail::arm_neon_constant::shift<true, true>(x, y); });
808 }
809
811 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
812 requires(Arch.has(arm_feature::neon) && std::is_signed_v<T> && sizeof(T) * N == 16 &&
813 (sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8))
814 native_nodiscard native_inline native_target("neon") constexpr auto
815 sqxtn(simd<T, N, Arch> a) noexcept {
816 using element =
817 std::conditional_t<sizeof(T) == 2, std::int8_t,
818 std::conditional_t<sizeof(T) == 4, std::int16_t, std::int32_t>>;
819 using result = simd<element, N, Arch>;
820 if consteval {
821 return detail::arm_neon_constant::narrow_low<result>(a);
822 } else {
823 if constexpr (sizeof(T) == 2)
824 return detail::arm_neon::from_register<result>(
825 detail::arm_neon::sqxtn(detail::arm_neon::to_register<int16x8_t>(a)));
826 else if constexpr (sizeof(T) == 4)
827 return detail::arm_neon::from_register<result>(
828 detail::arm_neon::sqxtn(detail::arm_neon::to_register<int32x4_t>(a)));
829 else if constexpr (sizeof(T) == 8)
830 return detail::arm_neon::from_register<result>(
831 detail::arm_neon::sqxtn(detail::arm_neon::to_register<int64x2_t>(a)));
832 }
833 }
834
836 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
837 requires(!Arch.has(arm_feature::neon) && std::is_signed_v<T> && sizeof(T) * N == 16 &&
838 (sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8) &&
839 requires { sizeof(simd<T, N, Arch>); })
840 native_nodiscard consteval auto sqxtn(simd<T, N, Arch> a) noexcept {
841 using element =
842 std::conditional_t<sizeof(T) == 2, std::int8_t,
843 std::conditional_t<sizeof(T) == 4, std::int16_t, std::int32_t>>;
844 using result = simd<element, N, Arch>;
845 return detail::arm_neon_constant::narrow_low<result>(a);
846 }
847
849 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
850 requires(Arch.has(arm_feature::neon) && std::is_signed_v<T> && sizeof(T) * N == 16 &&
851 (sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8))
853 simd<std::conditional_t<sizeof(T) == 2, std::int8_t,
854 std::conditional_t<sizeof(T) == 4, std::int16_t, std::int32_t>>,
855 N, Arch>
856 low,
857 simd<T, N, Arch> a) noexcept {
858 using element =
859 std::conditional_t<sizeof(T) == 2, std::int8_t,
860 std::conditional_t<sizeof(T) == 4, std::int16_t, std::int32_t>>;
861 using result = simd<element, 2 * N, Arch>;
862 if consteval {
863 return detail::arm_neon_constant::narrow_high<result>(low, a);
864 } else {
865 if constexpr (sizeof(T) == 2)
866 return detail::arm_neon::from_register<result>(
867 detail::arm_neon::sqxtn_high(detail::arm_neon::to_register<int8x8_t>(low),
868 detail::arm_neon::to_register<int16x8_t>(a)));
869 else if constexpr (sizeof(T) == 4)
870 return detail::arm_neon::from_register<result>(
871 detail::arm_neon::sqxtn_high(detail::arm_neon::to_register<int16x4_t>(low),
872 detail::arm_neon::to_register<int32x4_t>(a)));
873 else if constexpr (sizeof(T) == 8)
874 return detail::arm_neon::from_register<result>(
875 detail::arm_neon::sqxtn_high(detail::arm_neon::to_register<int32x2_t>(low),
876 detail::arm_neon::to_register<int64x2_t>(a)));
877 }
878 }
879
881 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
882 requires(!Arch.has(arm_feature::neon) && std::is_signed_v<T> && sizeof(T) * N == 16 &&
883 (sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8) &&
884 requires { sizeof(simd<T, N, Arch>); })
886 simd<std::conditional_t<sizeof(T) == 2, std::int8_t,
887 std::conditional_t<sizeof(T) == 4, std::int16_t, std::int32_t>>,
888 N, Arch>
889 low,
890 simd<T, N, Arch> a) noexcept {
891 using element =
892 std::conditional_t<sizeof(T) == 2, std::int8_t,
893 std::conditional_t<sizeof(T) == 4, std::int16_t, std::int32_t>>;
894 using result = simd<element, 2 * N, Arch>;
895 return detail::arm_neon_constant::narrow_high<result>(low, a);
896 }
897
899 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
900 requires(Arch.has(arm_feature::neon) && std::is_unsigned_v<T> && sizeof(T) * N == 16 &&
901 (sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8))
902 native_nodiscard native_inline native_target("neon") constexpr auto
903 uqxtn(simd<T, N, Arch> a) noexcept {
904 using element =
905 std::conditional_t<sizeof(T) == 2, std::uint8_t,
906 std::conditional_t<sizeof(T) == 4, std::uint16_t, std::uint32_t>>;
907 using result = simd<element, N, Arch>;
908 if consteval {
909 return detail::arm_neon_constant::narrow_low<result>(a);
910 } else {
911 if constexpr (sizeof(T) == 2)
912 return detail::arm_neon::from_register<result>(
913 detail::arm_neon::uqxtn(detail::arm_neon::to_register<uint16x8_t>(a)));
914 else if constexpr (sizeof(T) == 4)
915 return detail::arm_neon::from_register<result>(
916 detail::arm_neon::uqxtn(detail::arm_neon::to_register<uint32x4_t>(a)));
917 else if constexpr (sizeof(T) == 8)
918 return detail::arm_neon::from_register<result>(
919 detail::arm_neon::uqxtn(detail::arm_neon::to_register<uint64x2_t>(a)));
920 }
921 }
922
924 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
925 requires(!Arch.has(arm_feature::neon) && std::is_unsigned_v<T> && sizeof(T) * N == 16 &&
926 (sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8) &&
927 requires { sizeof(simd<T, N, Arch>); })
928 native_nodiscard consteval auto uqxtn(simd<T, N, Arch> a) noexcept {
929 using element =
930 std::conditional_t<sizeof(T) == 2, std::uint8_t,
931 std::conditional_t<sizeof(T) == 4, std::uint16_t, std::uint32_t>>;
932 using result = simd<element, N, Arch>;
933 return detail::arm_neon_constant::narrow_low<result>(a);
934 }
935
937 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
938 requires(Arch.has(arm_feature::neon) && std::is_unsigned_v<T> && sizeof(T) * N == 16 &&
939 (sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8))
941 simd<std::conditional_t<sizeof(T) == 2, std::uint8_t,
942 std::conditional_t<sizeof(T) == 4, std::uint16_t, std::uint32_t>>,
943 N, Arch>
944 low,
945 simd<T, N, Arch> a) noexcept {
946 using element =
947 std::conditional_t<sizeof(T) == 2, std::uint8_t,
948 std::conditional_t<sizeof(T) == 4, std::uint16_t, std::uint32_t>>;
949 using result = simd<element, 2 * N, Arch>;
950 if consteval {
951 return detail::arm_neon_constant::narrow_high<result>(low, a);
952 } else {
953 if constexpr (sizeof(T) == 2)
954 return detail::arm_neon::from_register<result>(
955 detail::arm_neon::uqxtn_high(detail::arm_neon::to_register<uint8x8_t>(low),
956 detail::arm_neon::to_register<uint16x8_t>(a)));
957 else if constexpr (sizeof(T) == 4)
958 return detail::arm_neon::from_register<result>(
959 detail::arm_neon::uqxtn_high(detail::arm_neon::to_register<uint16x4_t>(low),
960 detail::arm_neon::to_register<uint32x4_t>(a)));
961 else if constexpr (sizeof(T) == 8)
962 return detail::arm_neon::from_register<result>(
963 detail::arm_neon::uqxtn_high(detail::arm_neon::to_register<uint32x2_t>(low),
964 detail::arm_neon::to_register<uint64x2_t>(a)));
965 }
966 }
967
969 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
970 requires(!Arch.has(arm_feature::neon) && std::is_unsigned_v<T> && sizeof(T) * N == 16 &&
971 (sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8) &&
972 requires { sizeof(simd<T, N, Arch>); })
974 simd<std::conditional_t<sizeof(T) == 2, std::uint8_t,
975 std::conditional_t<sizeof(T) == 4, std::uint16_t, std::uint32_t>>,
976 N, Arch>
977 low,
978 simd<T, N, Arch> a) noexcept {
979 using element =
980 std::conditional_t<sizeof(T) == 2, std::uint8_t,
981 std::conditional_t<sizeof(T) == 4, std::uint16_t, std::uint32_t>>;
982 using result = simd<element, 2 * N, Arch>;
983 return detail::arm_neon_constant::narrow_high<result>(low, a);
984 }
985
987 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
988 requires(Arch.has(arm_feature::neon) && std::is_signed_v<T> && sizeof(T) * N == 16 &&
989 (sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8))
990 native_nodiscard native_inline native_target("neon") constexpr auto
991 sqxtun(simd<T, N, Arch> a) noexcept {
992 using element =
993 std::conditional_t<sizeof(T) == 2, std::uint8_t,
994 std::conditional_t<sizeof(T) == 4, std::uint16_t, std::uint32_t>>;
995 using result = simd<element, N, Arch>;
996 if consteval {
997 return detail::arm_neon_constant::narrow_low<result>(a);
998 } else {
999 if constexpr (sizeof(T) == 2)
1000 return detail::arm_neon::from_register<result>(
1001 detail::arm_neon::sqxtun(detail::arm_neon::to_register<int16x8_t>(a)));
1002 else if constexpr (sizeof(T) == 4)
1003 return detail::arm_neon::from_register<result>(
1004 detail::arm_neon::sqxtun(detail::arm_neon::to_register<int32x4_t>(a)));
1005 else if constexpr (sizeof(T) == 8)
1006 return detail::arm_neon::from_register<result>(
1007 detail::arm_neon::sqxtun(detail::arm_neon::to_register<int64x2_t>(a)));
1008 }
1009 }
1010
1012 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
1013 requires(!Arch.has(arm_feature::neon) && std::is_signed_v<T> && sizeof(T) * N == 16 &&
1014 (sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8) &&
1015 requires { sizeof(simd<T, N, Arch>); })
1016 native_nodiscard consteval auto sqxtun(simd<T, N, Arch> a) noexcept {
1017 using element =
1018 std::conditional_t<sizeof(T) == 2, std::uint8_t,
1019 std::conditional_t<sizeof(T) == 4, std::uint16_t, std::uint32_t>>;
1020 using result = simd<element, N, Arch>;
1021 return detail::arm_neon_constant::narrow_low<result>(a);
1022 }
1023
1025 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
1026 requires(Arch.has(arm_feature::neon) && std::is_signed_v<T> && sizeof(T) * N == 16 &&
1027 (sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8))
1029 simd<std::conditional_t<sizeof(T) == 2, std::uint8_t,
1030 std::conditional_t<sizeof(T) == 4, std::uint16_t, std::uint32_t>>,
1031 N, Arch>
1032 low,
1033 simd<T, N, Arch> a) noexcept {
1034 using element =
1035 std::conditional_t<sizeof(T) == 2, std::uint8_t,
1036 std::conditional_t<sizeof(T) == 4, std::uint16_t, std::uint32_t>>;
1037 using result = simd<element, 2 * N, Arch>;
1038 if consteval {
1039 return detail::arm_neon_constant::narrow_high<result>(low, a);
1040 } else {
1041 if constexpr (sizeof(T) == 2)
1042 return detail::arm_neon::from_register<result>(
1043 detail::arm_neon::sqxtun_high(detail::arm_neon::to_register<uint8x8_t>(low),
1044 detail::arm_neon::to_register<int16x8_t>(a)));
1045 else if constexpr (sizeof(T) == 4)
1046 return detail::arm_neon::from_register<result>(
1047 detail::arm_neon::sqxtun_high(detail::arm_neon::to_register<uint16x4_t>(low),
1048 detail::arm_neon::to_register<int32x4_t>(a)));
1049 else if constexpr (sizeof(T) == 8)
1050 return detail::arm_neon::from_register<result>(
1051 detail::arm_neon::sqxtun_high(detail::arm_neon::to_register<uint32x2_t>(low),
1052 detail::arm_neon::to_register<int64x2_t>(a)));
1053 }
1054 }
1055
1057 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
1058 requires(!Arch.has(arm_feature::neon) && std::is_signed_v<T> && sizeof(T) * N == 16 &&
1059 (sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8) &&
1060 requires { sizeof(simd<T, N, Arch>); })
1062 simd<std::conditional_t<sizeof(T) == 2, std::uint8_t,
1063 std::conditional_t<sizeof(T) == 4, std::uint16_t, std::uint32_t>>,
1064 N, Arch>
1065 low,
1066 simd<T, N, Arch> a) noexcept {
1067 using element =
1068 std::conditional_t<sizeof(T) == 2, std::uint8_t,
1069 std::conditional_t<sizeof(T) == 4, std::uint16_t, std::uint32_t>>;
1070 using result = simd<element, 2 * N, Arch>;
1071 return detail::arm_neon_constant::narrow_high<result>(low, a);
1072 }
1073
1075 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
1076 requires(Arch.has(arm_feature::neon) && (sizeof(T) <= 4) &&
1077 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
1078 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
1079 clz(simd<T, N, Arch> a) noexcept {
1080 if consteval {
1081 return detail::arm_neon_bits::unary(a, [](T value) {
1082 return T(std::countl_zero(std::make_unsigned_t<T>(value)));
1083 });
1084 } else {
1085 if constexpr (sizeof(T) == 1 && N == 8)
1086 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1087 vclz_u8(detail::arm_neon::to_register<uint8x8_t>(a)));
1088 else if constexpr (sizeof(T) == 1 && N == 16)
1089 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1090 vclzq_u8(detail::arm_neon::to_register<uint8x16_t>(a)));
1091 else if constexpr (sizeof(T) == 2 && N == 4)
1092 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1093 vclz_u16(detail::arm_neon::to_register<uint16x4_t>(a)));
1094 else if constexpr (sizeof(T) == 2 && N == 8)
1095 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1096 vclzq_u16(detail::arm_neon::to_register<uint16x8_t>(a)));
1097 else if constexpr (sizeof(T) == 4 && N == 2)
1098 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1099 vclz_u32(detail::arm_neon::to_register<uint32x2_t>(a)));
1100 else if constexpr (sizeof(T) == 4 && N == 4)
1101 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1102 vclzq_u32(detail::arm_neon::to_register<uint32x4_t>(a)));
1103 }
1104 }
1105
1107 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
1108 requires(Arch.has(arm_feature::neon) && std::is_signed_v<T> && (sizeof(T) <= 4) &&
1109 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
1110 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
1111 cls(simd<T, N, Arch> a) noexcept {
1112 if consteval {
1113 return detail::arm_neon_bits::unary(a, [](T value) {
1114 using U = std::make_unsigned_t<T>;
1115 U bits = U(value);
1116 if (value < 0)
1117 bits = U(~bits);
1118 return T(std::countl_zero(bits) - 1);
1119 });
1120 } else {
1121 if constexpr (sizeof(T) == 1 && N == 8)
1122 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1123 vcls_s8(detail::arm_neon::to_register<int8x8_t>(a)));
1124 else if constexpr (sizeof(T) == 1 && N == 16)
1125 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1126 vclsq_s8(detail::arm_neon::to_register<int8x16_t>(a)));
1127 else if constexpr (sizeof(T) == 2 && N == 4)
1128 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1129 vcls_s16(detail::arm_neon::to_register<int16x4_t>(a)));
1130 else if constexpr (sizeof(T) == 2 && N == 8)
1131 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1132 vclsq_s16(detail::arm_neon::to_register<int16x8_t>(a)));
1133 else if constexpr (sizeof(T) == 4 && N == 2)
1134 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1135 vcls_s32(detail::arm_neon::to_register<int32x2_t>(a)));
1136 else if constexpr (sizeof(T) == 4 && N == 4)
1137 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1138 vclsq_s32(detail::arm_neon::to_register<int32x4_t>(a)));
1139 }
1140 }
1141
1143 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
1144 requires(Arch.has(arm_feature::neon) && (sizeof(T) == 1) &&
1145 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
1146 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
1148 if consteval {
1149 return detail::arm_neon_bits::unary(a, [](T value) {
1150 std::uint8_t bits = std::uint8_t(value), result = 0;
1151 for (unsigned bit = 0; bit < 8; ++bit) {
1152 result = std::uint8_t((unsigned(result) << 1) | (bits & 1));
1153 bits >>= 1;
1154 }
1155 return std::bit_cast<T>(result);
1156 });
1157 } else {
1158 if constexpr (sizeof(T) == 1 && N == 8)
1159 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1160 vrbit_u8(detail::arm_neon::to_register<uint8x8_t>(a)));
1161 else if constexpr (sizeof(T) == 1 && N == 16)
1162 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1163 vrbitq_u8(detail::arm_neon::to_register<uint8x16_t>(a)));
1164 }
1165 }
1166
1168 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
1169 requires(Arch.has(arm_feature::neon) && (sizeof(T) == 1) &&
1170 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
1171 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
1173 if consteval {
1174 return detail::arm_neon_bits::reverse<16>(a);
1175 } else {
1176 if constexpr (sizeof(T) == 1 && N == 8)
1177 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1178 vrev16_u8(detail::arm_neon::to_register<uint8x8_t>(a)));
1179 else if constexpr (sizeof(T) == 1 && N == 16)
1180 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1181 vrev16q_u8(detail::arm_neon::to_register<uint8x16_t>(a)));
1182 }
1183 }
1184
1186 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
1187 requires(Arch.has(arm_feature::neon) && (sizeof(T) <= 2) &&
1188 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
1189 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
1191 if consteval {
1192 return detail::arm_neon_bits::reverse<32>(a);
1193 } else {
1194 if constexpr (sizeof(T) == 1 && N == 8)
1195 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1196 vrev32_u8(detail::arm_neon::to_register<uint8x8_t>(a)));
1197 else if constexpr (sizeof(T) == 1 && N == 16)
1198 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1199 vrev32q_u8(detail::arm_neon::to_register<uint8x16_t>(a)));
1200 else if constexpr (sizeof(T) == 2 && N == 4)
1201 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1202 vrev32_u16(detail::arm_neon::to_register<uint16x4_t>(a)));
1203 else if constexpr (sizeof(T) == 2 && N == 8)
1204 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1205 vrev32q_u16(detail::arm_neon::to_register<uint16x8_t>(a)));
1206 }
1207 }
1208
1210 template<isa<arm> Arch, simd_integer_element T, std::size_t N>
1211 requires(Arch.has(arm_feature::neon) && (sizeof(T) <= 4) &&
1212 (sizeof(T) * N == 8 || sizeof(T) * N == 16))
1213 native_nodiscard native_inline native_target("neon") constexpr simd<T, N, Arch>
1215 if consteval {
1216 return detail::arm_neon_bits::reverse<64>(a);
1217 } else {
1218 if constexpr (sizeof(T) == 1 && N == 8)
1219 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1220 vrev64_u8(detail::arm_neon::to_register<uint8x8_t>(a)));
1221 else if constexpr (sizeof(T) == 1 && N == 16)
1222 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1223 vrev64q_u8(detail::arm_neon::to_register<uint8x16_t>(a)));
1224 else if constexpr (sizeof(T) == 2 && N == 4)
1225 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1226 vrev64_u16(detail::arm_neon::to_register<uint16x4_t>(a)));
1227 else if constexpr (sizeof(T) == 2 && N == 8)
1228 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1229 vrev64q_u16(detail::arm_neon::to_register<uint16x8_t>(a)));
1230 else if constexpr (sizeof(T) == 4 && N == 2)
1231 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1232 vrev64_u32(detail::arm_neon::to_register<uint32x2_t>(a)));
1233 else if constexpr (sizeof(T) == 4 && N == 4)
1234 return detail::arm_neon::from_register<simd<T, N, Arch>>(
1235 vrev64q_u32(detail::arm_neon::to_register<uint32x4_t>(a)));
1236 }
1237 }
1238
1240} // namespace native
1241#endif
constexpr simd< T, N, Arch > sqshl(simd< T, N, Arch > a, simd< std::make_signed_t< T >, N, Arch > b) noexcept
constexpr simd< T, N, Arch > rev32(simd< T, N, Arch > a) noexcept
Reverse byte or halfword lanes within each 32-bit block.
constexpr simd< T, N, Arch > ushl(simd< T, N, Arch > a, simd< std::make_signed_t< T >, N, Arch > b) noexcept
Shift by each count lane's signed low byte; negative counts shift right.
constexpr simd< T, N, Arch > urshl(simd< T, N, Arch > a, simd< std::make_signed_t< T >, N, Arch > b) noexcept
Shift by each count lane's signed low byte; negative counts shift right with rounding.
constexpr simd< T, N, Arch > sqdmulh(simd< T, N, Arch > a, simd< T, N, Arch > b) noexcept
Signed doubled multiply-high, saturating the minimum-times-minimum case.
constexpr simd< T, N, Arch > sqadd(simd< T, N, Arch > a, simd< T, N, Arch > b) noexcept
Signed saturating lane addition.
constexpr simd< T, N, Arch > srshl(simd< T, N, Arch > a, simd< std::make_signed_t< T >, N, Arch > b) noexcept
Shift by each count lane's signed low byte; negative counts shift right with rounding.
constexpr auto sqxtun_high(simd< std::conditional_t< sizeof(T)==2, std::uint8_t, std::conditional_t< sizeof(T)==4, std::uint16_t, std::uint32_t > >, N, Arch > low, simd< T, N, Arch > a) noexcept
Narrow with saturation and append above the preserved low half.
constexpr simd< T, N, Arch > cls(simd< T, N, Arch > a) noexcept
Count leading sign bits in each lane, excluding the sign bit itself.
constexpr simd< T, N, Arch > sqrdmulh(simd< T, N, Arch > a, simd< T, N, Arch > b) noexcept
Signed doubled multiply-high with rounding before final saturation.
constexpr simd< T, N, Arch > uqsub(simd< T, N, Arch > a, simd< T, N, Arch > b) noexcept
Unsigned saturating lane subtraction.
constexpr simd< T, N, Arch > rev64(simd< T, N, Arch > a) noexcept
Reverse byte, halfword or word lanes within each 64-bit block.
constexpr auto uqxtn(simd< T, N, Arch > a) noexcept
Narrow 128 bits with saturation to a 64-bit result.
constexpr simd< T, N, Arch > sqrshl(simd< T, N, Arch > a, simd< std::make_signed_t< T >, N, Arch > b) noexcept
constexpr simd< T, N, Arch > uqrshl(simd< T, N, Arch > a, simd< std::make_signed_t< T >, N, Arch > b) noexcept
constexpr simd< T, N, Arch > uqadd(simd< T, N, Arch > a, simd< T, N, Arch > b) noexcept
Unsigned saturating lane addition.
constexpr auto uqxtn_high(simd< std::conditional_t< sizeof(T)==2, std::uint8_t, std::conditional_t< sizeof(T)==4, std::uint16_t, std::uint32_t > >, N, Arch > low, simd< T, N, Arch > a) noexcept
Narrow with saturation and append above the preserved low half.
constexpr simd< T, N, Arch > rev16(simd< T, N, Arch > a) noexcept
Reverse byte lanes within each 16-bit block.
constexpr auto sqxtun(simd< T, N, Arch > a) noexcept
Narrow 128 bits with saturation to a 64-bit result.
constexpr simd< T, N, Arch > uqshl(simd< T, N, Arch > a, simd< std::make_signed_t< T >, N, Arch > b) noexcept
constexpr simd< T, N, Arch > rbit(simd< T, N, Arch > a) noexcept
Reverse the eight bits within each byte lane.
constexpr auto sqxtn_high(simd< std::conditional_t< sizeof(T)==2, std::int8_t, std::conditional_t< sizeof(T)==4, std::int16_t, std::int32_t > >, N, Arch > low, simd< T, N, Arch > a) noexcept
Narrow with saturation and append above the preserved low half.
constexpr simd< T, N, Arch > clz(simd< T, N, Arch > a) noexcept
Count leading zero bits in each lane, including the full width for zero.
constexpr simd< T, N, Arch > sqsub(simd< T, N, Arch > a, simd< T, N, Arch > b) noexcept
Signed saturating lane subtraction.
constexpr auto sqxtn(simd< T, N, Arch > a) noexcept
Narrow 128 bits with saturation to a 64-bit result.
constexpr simd< T, N, Arch > sshl(simd< T, N, Arch > a, simd< std::make_signed_t< T >, N, Arch > b) noexcept
Shift by each count lane's signed low byte; negative counts shift right.
#define native_inline
inline [[always_inline]]
Definition attributes.h:212
#define native_nodiscard
C++17 [[nodiscard]].
Definition attributes.h:189
#define native_target(x)
this indicates a required feature set for the current multiversioned function.
Definition attributes.h:476
Architecture-tagged vectors, register packs and supporting value types. Native arithmetic follows its...
Standard-library adaptations documented here for SIMD value types.
Omitted architecture arguments use the native.simd provider's baseline.