3#include "native/isa_import.h"
5#include "native/arm/neon.h"
6#include "native/arm/neon_constant.h"
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);
19 template<
unsigned Bits,
class V>
consteval V reverse(V input)
noexcept {
20 auto source = arm_constant::lanes(input);
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);
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))
46 return detail::arm_neon_constant::binary(
47 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::add(x, y); });
49 if constexpr (
sizeof(T) == 1 && N == 8)
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)
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)
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)
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)
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)
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)
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)
79 detail::arm_neon::sqadd(detail::arm_neon::to_register<int64x2_t>(a),
80 detail::arm_neon::to_register<int64x2_t>(b)));
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>); })
91 return detail::arm_neon_constant::binary(
92 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::add(x, y); });
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))
103 return detail::arm_neon_constant::binary(
104 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::add(x, y); });
106 if constexpr (
sizeof(T) == 1 && N == 8)
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)
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)
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)
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)
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)
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)
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)
136 detail::arm_neon::uqadd(detail::arm_neon::to_register<uint64x2_t>(a),
137 detail::arm_neon::to_register<uint64x2_t>(b)));
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>); })
148 return detail::arm_neon_constant::binary(
149 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::add(x, y); });
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))
160 return detail::arm_neon_constant::binary(
161 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::sub(x, y); });
163 if constexpr (
sizeof(T) == 1 && N == 8)
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)
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)
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)
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)
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)
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)
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)
193 detail::arm_neon::sqsub(detail::arm_neon::to_register<int64x2_t>(a),
194 detail::arm_neon::to_register<int64x2_t>(b)));
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>); })
205 return detail::arm_neon_constant::binary(
206 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::sub(x, y); });
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))
217 return detail::arm_neon_constant::binary(
218 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::sub(x, y); });
220 if constexpr (
sizeof(T) == 1 && N == 8)
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)
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)
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)
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)
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)
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)
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)
250 detail::arm_neon::uqsub(detail::arm_neon::to_register<uint64x2_t>(a),
251 detail::arm_neon::to_register<uint64x2_t>(b)));
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>); })
262 return detail::arm_neon_constant::binary(
263 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::sub(x, y); });
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))
273 return detail::arm_neon_constant::binary(a, b, [](
auto x,
auto y) {
274 return detail::arm_neon_constant::multiply_high<false>(x, y);
277 if constexpr (
sizeof(T) == 2 && N == 4)
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)
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)
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)
291 detail::arm_neon::sqdmulh(detail::arm_neon::to_register<int32x4_t>(a),
292 detail::arm_neon::to_register<int32x4_t>(b)));
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>); })
303 return detail::arm_neon_constant::binary(
304 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::multiply_high<false>(x, y); });
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))
314 return detail::arm_neon_constant::binary(a, b, [](
auto x,
auto y) {
315 return detail::arm_neon_constant::multiply_high<true>(x, y);
318 if constexpr (
sizeof(T) == 2 && N == 4)
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)
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)
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)
332 detail::arm_neon::sqrdmulh(detail::arm_neon::to_register<int32x4_t>(a),
333 detail::arm_neon::to_register<int32x4_t>(b)));
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>); })
344 return detail::arm_neon_constant::binary(
345 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::multiply_high<true>(x, y); });
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))
356 return detail::arm_neon_constant::binary(a, b, [](
auto x,
auto y) {
357 return detail::arm_neon_constant::shift<false, false>(x, y);
360 if constexpr (
sizeof(T) == 1 && N == 8)
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)
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)
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)
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)
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)
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)
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)
390 detail::arm_neon::sshl(detail::arm_neon::to_register<int64x2_t>(a),
391 detail::arm_neon::to_register<int64x2_t>(b)));
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>); })
402 return detail::arm_neon_constant::binary(
403 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::shift<false, false>(x, y); });
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))
414 return detail::arm_neon_constant::binary(
415 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::shift<true, false>(x, y); });
417 if constexpr (
sizeof(T) == 1 && N == 8)
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)
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)
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)
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)
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)
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)
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)
447 detail::arm_neon::srshl(detail::arm_neon::to_register<int64x2_t>(a),
448 detail::arm_neon::to_register<int64x2_t>(b)));
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>); })
459 return detail::arm_neon_constant::binary(
460 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::shift<true, false>(x, y); });
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))
472 return detail::arm_neon_constant::binary(
473 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::shift<false, true>(x, y); });
475 if constexpr (
sizeof(T) == 1 && N == 8)
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)
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)
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)
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)
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)
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)
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)
505 detail::arm_neon::sqshl(detail::arm_neon::to_register<int64x2_t>(a),
506 detail::arm_neon::to_register<int64x2_t>(b)));
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>); })
517 return detail::arm_neon_constant::binary(
518 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::shift<false, true>(x, y); });
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))
530 return detail::arm_neon_constant::binary(
531 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::shift<true, true>(x, y); });
533 if constexpr (
sizeof(T) == 1 && N == 8)
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)
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)
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)
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)
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)
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)
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)
563 detail::arm_neon::sqrshl(detail::arm_neon::to_register<int64x2_t>(a),
564 detail::arm_neon::to_register<int64x2_t>(b)));
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>); })
575 return detail::arm_neon_constant::binary(
576 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::shift<true, true>(x, y); });
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))
587 return detail::arm_neon_constant::binary(a, b, [](
auto x,
auto y) {
588 return detail::arm_neon_constant::shift<false, false>(x, y);
591 if constexpr (
sizeof(T) == 1 && N == 8)
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)
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)
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)
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)
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)
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)
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)
621 detail::arm_neon::ushl(detail::arm_neon::to_register<uint64x2_t>(a),
622 detail::arm_neon::to_register<int64x2_t>(b)));
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>); })
633 return detail::arm_neon_constant::binary(
634 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::shift<false, false>(x, y); });
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))
645 return detail::arm_neon_constant::binary(
646 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::shift<true, false>(x, y); });
648 if constexpr (
sizeof(T) == 1 && N == 8)
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)
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)
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)
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)
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)
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)
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)
678 detail::arm_neon::urshl(detail::arm_neon::to_register<uint64x2_t>(a),
679 detail::arm_neon::to_register<int64x2_t>(b)));
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>); })
690 return detail::arm_neon_constant::binary(
691 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::shift<true, false>(x, y); });
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))
703 return detail::arm_neon_constant::binary(
704 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::shift<false, true>(x, y); });
706 if constexpr (
sizeof(T) == 1 && N == 8)
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)
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)
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)
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)
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)
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)
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)
736 detail::arm_neon::uqshl(detail::arm_neon::to_register<uint64x2_t>(a),
737 detail::arm_neon::to_register<int64x2_t>(b)));
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>); })
748 return detail::arm_neon_constant::binary(
749 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::shift<false, true>(x, y); });
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))
761 return detail::arm_neon_constant::binary(
762 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::shift<true, true>(x, y); });
764 if constexpr (
sizeof(T) == 1 && N == 8)
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)
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)
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)
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)
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)
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)
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)
794 detail::arm_neon::uqrshl(detail::arm_neon::to_register<uint64x2_t>(a),
795 detail::arm_neon::to_register<int64x2_t>(b)));
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>); })
806 return detail::arm_neon_constant::binary(
807 a, b, [](
auto x,
auto y) {
return detail::arm_neon_constant::shift<true, true>(x, y); });
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))
817 std::conditional_t<
sizeof(T) == 2, std::int8_t,
818 std::conditional_t<
sizeof(T) == 4, std::int16_t, std::int32_t>>;
821 return detail::arm_neon_constant::narrow_low<result>(a);
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)));
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>); })
842 std::conditional_t<
sizeof(T) == 2, std::int8_t,
843 std::conditional_t<
sizeof(T) == 4, std::int16_t, std::int32_t>>;
845 return detail::arm_neon_constant::narrow_low<result>(a);
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>>,
857 simd<T, N, Arch> a) noexcept {
859 std::conditional_t<
sizeof(T) == 2, std::int8_t,
860 std::conditional_t<
sizeof(T) == 4, std::int16_t, std::int32_t>>;
863 return detail::arm_neon_constant::narrow_high<result>(low, a);
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)));
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>>,
892 std::conditional_t<
sizeof(T) == 2, std::int8_t,
893 std::conditional_t<
sizeof(T) == 4, std::int16_t, std::int32_t>>;
895 return detail::arm_neon_constant::narrow_high<result>(low, a);
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))
905 std::conditional_t<
sizeof(T) == 2, std::uint8_t,
906 std::conditional_t<
sizeof(T) == 4, std::uint16_t, std::uint32_t>>;
909 return detail::arm_neon_constant::narrow_low<result>(a);
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)));
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>); })
930 std::conditional_t<
sizeof(T) == 2, std::uint8_t,
931 std::conditional_t<
sizeof(T) == 4, std::uint16_t, std::uint32_t>>;
933 return detail::arm_neon_constant::narrow_low<result>(a);
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>>,
945 simd<T, N, Arch> a) noexcept {
947 std::conditional_t<
sizeof(T) == 2, std::uint8_t,
948 std::conditional_t<
sizeof(T) == 4, std::uint16_t, std::uint32_t>>;
951 return detail::arm_neon_constant::narrow_high<result>(low, a);
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)));
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>>,
980 std::conditional_t<
sizeof(T) == 2, std::uint8_t,
981 std::conditional_t<
sizeof(T) == 4, std::uint16_t, std::uint32_t>>;
983 return detail::arm_neon_constant::narrow_high<result>(low, a);
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))
993 std::conditional_t<
sizeof(T) == 2, std::uint8_t,
994 std::conditional_t<
sizeof(T) == 4, std::uint16_t, std::uint32_t>>;
997 return detail::arm_neon_constant::narrow_low<result>(a);
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)));
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>); })
1018 std::conditional_t<
sizeof(T) == 2, std::uint8_t,
1019 std::conditional_t<
sizeof(T) == 4, std::uint16_t, std::uint32_t>>;
1021 return detail::arm_neon_constant::narrow_low<result>(a);
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>>,
1033 simd<T, N, Arch> a) noexcept {
1035 std::conditional_t<
sizeof(T) == 2, std::uint8_t,
1036 std::conditional_t<
sizeof(T) == 4, std::uint16_t, std::uint32_t>>;
1039 return detail::arm_neon_constant::narrow_high<result>(low, a);
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)));
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>>,
1068 std::conditional_t<
sizeof(T) == 2, std::uint8_t,
1069 std::conditional_t<
sizeof(T) == 4, std::uint16_t, std::uint32_t>>;
1071 return detail::arm_neon_constant::narrow_high<result>(low, a);
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))
1081 return detail::arm_neon_bits::unary(a, [](T value) {
1082 return T(std::countl_zero(std::make_unsigned_t<T>(value)));
1085 if constexpr (
sizeof(T) == 1 && N == 8)
1087 vclz_u8(detail::arm_neon::to_register<uint8x8_t>(a)));
1088 else if constexpr (
sizeof(T) == 1 && N == 16)
1090 vclzq_u8(detail::arm_neon::to_register<uint8x16_t>(a)));
1091 else if constexpr (
sizeof(T) == 2 && N == 4)
1093 vclz_u16(detail::arm_neon::to_register<uint16x4_t>(a)));
1094 else if constexpr (
sizeof(T) == 2 && N == 8)
1096 vclzq_u16(detail::arm_neon::to_register<uint16x8_t>(a)));
1097 else if constexpr (
sizeof(T) == 4 && N == 2)
1099 vclz_u32(detail::arm_neon::to_register<uint32x2_t>(a)));
1100 else if constexpr (
sizeof(T) == 4 && N == 4)
1102 vclzq_u32(detail::arm_neon::to_register<uint32x4_t>(a)));
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))
1113 return detail::arm_neon_bits::unary(a, [](T value) {
1114 using U = std::make_unsigned_t<T>;
1118 return T(std::countl_zero(bits) - 1);
1121 if constexpr (
sizeof(T) == 1 && N == 8)
1123 vcls_s8(detail::arm_neon::to_register<int8x8_t>(a)));
1124 else if constexpr (
sizeof(T) == 1 && N == 16)
1126 vclsq_s8(detail::arm_neon::to_register<int8x16_t>(a)));
1127 else if constexpr (
sizeof(T) == 2 && N == 4)
1129 vcls_s16(detail::arm_neon::to_register<int16x4_t>(a)));
1130 else if constexpr (
sizeof(T) == 2 && N == 8)
1132 vclsq_s16(detail::arm_neon::to_register<int16x8_t>(a)));
1133 else if constexpr (
sizeof(T) == 4 && N == 2)
1135 vcls_s32(detail::arm_neon::to_register<int32x2_t>(a)));
1136 else if constexpr (
sizeof(T) == 4 && N == 4)
1138 vclsq_s32(detail::arm_neon::to_register<int32x4_t>(a)));
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))
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));
1155 return std::bit_cast<T>(result);
1158 if constexpr (
sizeof(T) == 1 && N == 8)
1160 vrbit_u8(detail::arm_neon::to_register<uint8x8_t>(a)));
1161 else if constexpr (
sizeof(T) == 1 && N == 16)
1163 vrbitq_u8(detail::arm_neon::to_register<uint8x16_t>(a)));
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))
1174 return detail::arm_neon_bits::reverse<16>(a);
1176 if constexpr (
sizeof(T) == 1 && N == 8)
1178 vrev16_u8(detail::arm_neon::to_register<uint8x8_t>(a)));
1179 else if constexpr (
sizeof(T) == 1 && N == 16)
1181 vrev16q_u8(detail::arm_neon::to_register<uint8x16_t>(a)));
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))
1192 return detail::arm_neon_bits::reverse<32>(a);
1194 if constexpr (
sizeof(T) == 1 && N == 8)
1196 vrev32_u8(detail::arm_neon::to_register<uint8x8_t>(a)));
1197 else if constexpr (
sizeof(T) == 1 && N == 16)
1199 vrev32q_u8(detail::arm_neon::to_register<uint8x16_t>(a)));
1200 else if constexpr (
sizeof(T) == 2 && N == 4)
1202 vrev32_u16(detail::arm_neon::to_register<uint16x4_t>(a)));
1203 else if constexpr (
sizeof(T) == 2 && N == 8)
1205 vrev32q_u16(detail::arm_neon::to_register<uint16x8_t>(a)));
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))
1216 return detail::arm_neon_bits::reverse<64>(a);
1218 if constexpr (
sizeof(T) == 1 && N == 8)
1220 vrev64_u8(detail::arm_neon::to_register<uint8x8_t>(a)));
1221 else if constexpr (
sizeof(T) == 1 && N == 16)
1223 vrev64q_u8(detail::arm_neon::to_register<uint8x16_t>(a)));
1224 else if constexpr (
sizeof(T) == 2 && N == 4)
1226 vrev64_u16(detail::arm_neon::to_register<uint16x4_t>(a)));
1227 else if constexpr (
sizeof(T) == 2 && N == 8)
1229 vrev64q_u16(detail::arm_neon::to_register<uint16x8_t>(a)));
1230 else if constexpr (
sizeof(T) == 4 && N == 2)
1232 vrev64_u32(detail::arm_neon::to_register<uint32x2_t>(a)));
1233 else if constexpr (
sizeof(T) == 4 && N == 4)
1235 vrev64q_u32(detail::arm_neon::to_register<uint32x4_t>(a)));
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]]
#define native_nodiscard
C++17 [[nodiscard]].
#define native_target(x)
this indicates a required feature set for the current multiversioned function.
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.