1#ifndef NEFORCE_CORE_SIMD_ARITHMETIC_HPP__
2#define NEFORCE_CORE_SIMD_ARITHMETIC_HPP__
13NEFORCE_BEGIN_NAMESPACE__
28#ifdef NEFORCE_SIMD_SSE2
29 return ::_mm_add_epi8(a, b);
30#elif defined(NEFORCE_SIMD_NEON)
31 return ::vreinterpretq_u8_s8(::vaddq_s8(::vreinterpretq_s8_u8(a), ::vreinterpretq_s8_u8(b)));
34 for (
int i = 0; i < 16; ++i) {
35 result.data[i] =
static_cast<byte_t>(
static_cast<int8_t>(a.data[i]) +
static_cast<int8_t>(b.data[i]));
48#ifdef NEFORCE_SIMD_SSE2
49 return ::_mm_add_epi16(a, b);
50#elif defined(NEFORCE_SIMD_NEON)
51 return ::vreinterpretq_u8_s16(::vaddq_s16(::vreinterpretq_s16_u8(a), ::vreinterpretq_s16_u8(b)));
53 const auto* sa =
reinterpret_cast<const int16_t*
>(a.data);
54 const auto* sb =
reinterpret_cast<const int16_t*
>(b.data);
56 auto* rd =
reinterpret_cast<int16_t*
>(result.data);
57 for (
int i = 0; i < 8; ++i) {
58 rd[i] =
static_cast<int16_t>(sa[i] + sb[i]);
71#ifdef NEFORCE_SIMD_SSE2
72 return ::_mm_add_epi32(a, b);
73#elif defined(NEFORCE_SIMD_NEON)
74 return ::vreinterpretq_u8_s32(::vaddq_s32(::vreinterpretq_s32_u8(a), ::vreinterpretq_s32_u8(b)));
76 const auto* sa =
reinterpret_cast<const int32_t*
>(a.data);
77 const auto* sb =
reinterpret_cast<const int32_t*
>(b.data);
79 auto* rd =
reinterpret_cast<int32_t*
>(result.data);
80 for (
int i = 0; i < 4; ++i) {
81 rd[i] = sa[i] + sb[i];
94#ifdef NEFORCE_SIMD_SSE2
95 return ::_mm_add_epi64(a, b);
96#elif defined(NEFORCE_SIMD_NEON)
97 return ::vreinterpretq_u8_s64(::vaddq_s64(::vreinterpretq_s64_u8(a), ::vreinterpretq_s64_u8(b)));
99 const auto* sa =
reinterpret_cast<const int64_t*
>(a.data);
100 const auto* sb =
reinterpret_cast<const int64_t*
>(b.data);
102 auto* rd =
reinterpret_cast<int64_t*
>(result.data);
103 for (
int i = 0; i < 2; ++i) {
104 rd[i] = sa[i] + sb[i];
117#ifdef NEFORCE_SIMD_SSE2
118 return ::_mm_sub_epi8(a, b);
119#elif defined(NEFORCE_SIMD_NEON)
120 return ::vreinterpretq_u8_s8(::vsubq_s8(::vreinterpretq_s8_u8(a), ::vreinterpretq_s8_u8(b)));
123 for (
int i = 0; i < 16; ++i) {
124 result.data[i] =
static_cast<byte_t>(
static_cast<int8_t>(a.data[i]) -
static_cast<int8_t>(b.data[i]));
137#ifdef NEFORCE_SIMD_SSE2
138 return ::_mm_sub_epi16(a, b);
139#elif defined(NEFORCE_SIMD_NEON)
140 return ::vreinterpretq_u8_s16(::vsubq_s16(::vreinterpretq_s16_u8(a), ::vreinterpretq_s16_u8(b)));
142 const auto* sa =
reinterpret_cast<const int16_t*
>(a.data);
143 const auto* sb =
reinterpret_cast<const int16_t*
>(b.data);
145 auto* rd =
reinterpret_cast<int16_t*
>(result.data);
146 for (
int i = 0; i < 8; ++i) {
147 rd[i] =
static_cast<int16_t>(sa[i] - sb[i]);
160#ifdef NEFORCE_SIMD_SSE2
161 return ::_mm_sub_epi32(a, b);
162#elif defined(NEFORCE_SIMD_NEON)
163 return ::vreinterpretq_u8_s32(::vsubq_s32(::vreinterpretq_s32_u8(a), ::vreinterpretq_s32_u8(b)));
165 const auto* sa =
reinterpret_cast<const int32_t*
>(a.data);
166 const auto* sb =
reinterpret_cast<const int32_t*
>(b.data);
168 auto* rd =
reinterpret_cast<int32_t*
>(result.data);
169 for (
int i = 0; i < 4; ++i) {
170 rd[i] = sa[i] - sb[i];
183#ifdef NEFORCE_SIMD_SSE2
184 return ::_mm_sub_epi64(a, b);
185#elif defined(NEFORCE_SIMD_NEON)
186 return ::vreinterpretq_u8_s64(::vsubq_s64(::vreinterpretq_s64_u8(a), ::vreinterpretq_s64_u8(b)));
188 const auto* sa =
reinterpret_cast<const int64_t*
>(a.data);
189 const auto* sb =
reinterpret_cast<const int64_t*
>(b.data);
191 auto* rd =
reinterpret_cast<int64_t*
>(result.data);
192 for (
int i = 0; i < 2; ++i) {
193 rd[i] = sa[i] - sb[i];
206#ifdef NEFORCE_SIMD_SSE2
207 return ::_mm_mullo_epi16(a, b);
208#elif defined(NEFORCE_SIMD_NEON)
209 return ::vreinterpretq_u8_s16(::vmulq_s16(::vreinterpretq_s16_u8(a), ::vreinterpretq_s16_u8(b)));
211 const auto* sa =
reinterpret_cast<const int16_t*
>(a.data);
212 const auto* sb =
reinterpret_cast<const int16_t*
>(b.data);
214 auto* rd =
reinterpret_cast<int16_t*
>(result.data);
215 for (
int i = 0; i < 8; ++i) {
216 rd[i] =
static_cast<int16_t>(sa[i] * sb[i]);
229#if defined(__SSE4_1__) || defined(NEFORCE_SIMD_AVX2)
230 return ::_mm_mullo_epi32(a, b);
231#elif defined(NEFORCE_SIMD_SSE2)
232 const ::__m128i prod_even = ::_mm_mul_epu32(a, b);
233 const ::__m128i prod_odd = ::_mm_mul_epu32(::_mm_srli_epi64(a, 32), ::_mm_srli_epi64(b, 32));
234 const ::__m128i shuf_even = _mm_shuffle_epi32(prod_even, _MM_SHUFFLE(2, 0, 2, 0));
235 const ::__m128i shuf_odd = _mm_shuffle_epi32(prod_odd, _MM_SHUFFLE(2, 0, 2, 0));
236 return ::_mm_unpacklo_epi32(shuf_even, shuf_odd);
237#elif defined(NEFORCE_SIMD_NEON)
238 return ::vreinterpretq_u8_s32(::vmulq_s32(::vreinterpretq_s32_u8(a), ::vreinterpretq_s32_u8(b)));
240 const auto* sa =
reinterpret_cast<const int32_t*
>(a.data);
241 const auto* sb =
reinterpret_cast<const int32_t*
>(b.data);
243 auto* rd =
reinterpret_cast<int32_t*
>(result.data);
244 for (
int i = 0; i < 4; ++i) {
245 rd[i] =
static_cast<int32_t>(sa[i] * sb[i]);
258#ifdef NEFORCE_SIMD_SSE2
259 return ::_mm_mulhi_epi16(a, b);
260#elif defined(NEFORCE_SIMD_NEON)
261 const ::int16x8_t sa = ::vreinterpretq_s16_u8(a);
262 const ::int16x8_t sb = ::vreinterpretq_s16_u8(b);
263 const ::int16x4_t a_lo = ::vget_low_s16(sa);
264 const ::int16x4_t b_lo = ::vget_low_s16(sb);
265 const ::int16x4_t a_hi = ::vget_high_s16(sa);
266 const ::int16x4_t b_hi = ::vget_high_s16(sb);
267 const ::int32x4_t prod_lo = ::vmull_s16(a_lo, b_lo);
268 const ::int32x4_t prod_hi = ::vmull_s16(a_hi, b_hi);
269 const ::int16x4_t hi_lo = vshrn_n_s32(prod_lo, 16);
270 const ::int16x4_t hi_hi = vshrn_n_s32(prod_hi, 16);
271 return ::vreinterpretq_u8_s16(::vcombine_s16(hi_lo, hi_hi));
273 const auto* sa =
reinterpret_cast<const int16_t*
>(a.data);
274 const auto* sb =
reinterpret_cast<const int16_t*
>(b.data);
276 auto* rd =
reinterpret_cast<int16_t*
>(result.data);
277 for (
int i = 0; i < 8; ++i) {
292#if defined(__SSSE3__) || defined(NEFORCE_SIMD_AVX2)
293 return ::_mm_maddubs_epi16(a, b);
294#elif defined(NEFORCE_SIMD_SSE2)
295 const auto* sa =
reinterpret_cast<const int8_t*
>(&a);
296 const auto* sb =
reinterpret_cast<const int8_t*
>(&b);
298 for (
int i = 0; i < 8; ++i) {
304 return ::_mm_load_si128(
reinterpret_cast<const ::__m128i*
>(result));
305#elif defined(NEFORCE_SIMD_NEON)
306 const ::int8x16_t sa = ::vreinterpretq_s8_u8(a);
307 const ::int8x16_t sb = ::vreinterpretq_s8_u8(b);
308 const ::int16x8_t prod = ::vmull_s8(::vget_low_s8(sa), ::vget_low_s8(sb));
309 const ::int16x8_t prod_hi = ::vmull_s8(::vget_high_s8(sa), ::vget_high_s8(sb));
310 return ::vreinterpretq_u8_s16(::vpaddq_s16(prod, prod_hi));
312 const auto* sa =
reinterpret_cast<const int8_t*
>(a.data);
313 const auto* sb =
reinterpret_cast<const int8_t*
>(b.data);
315 auto* rd =
reinterpret_cast<int16_t*
>(result.data);
316 for (
int i = 0; i < 8; ++i) {
333#ifdef NEFORCE_SIMD_SSE2
334 return ::_mm_adds_epi8(a, b);
335#elif defined(NEFORCE_SIMD_NEON)
336 return ::vreinterpretq_u8_s8(::vqaddq_s8(::vreinterpretq_s8_u8(a), ::vreinterpretq_s8_u8(b)));
339 for (
int i = 0; i < 16; ++i) {
340 const int val =
static_cast<int8_t>(a.data[i]) +
static_cast<int8_t>(b.data[i]);
342 result.data[i] = 127;
343 }
else if (val < -128) {
344 result.data[i] = 128;
346 result.data[i] =
static_cast<byte_t>(
static_cast<int8_t>(val));
360#ifdef NEFORCE_SIMD_SSE2
361 return ::_mm_adds_epi16(a, b);
362#elif defined(NEFORCE_SIMD_NEON)
363 return ::vreinterpretq_u8_s16(::vqaddq_s16(::vreinterpretq_s16_u8(a), ::vreinterpretq_s16_u8(b)));
365 const auto* sa =
reinterpret_cast<const int16_t*
>(a.data);
366 const auto* sb =
reinterpret_cast<const int16_t*
>(b.data);
368 auto* rd =
reinterpret_cast<int16_t*
>(result.data);
369 for (
int i = 0; i < 8; ++i) {
370 const int val = sa[i] + sb[i];
373 }
else if (val < -32768) {
376 rd[i] =
static_cast<int16_t>(val);
390#ifdef NEFORCE_SIMD_SSE2
391 return ::_mm_adds_epu8(a, b);
392#elif defined(NEFORCE_SIMD_NEON)
393 return ::vqaddq_u8(a, b);
396 for (
int i = 0; i < 16; ++i) {
397 const int val =
static_cast<int>(a.data[i]) +
static_cast<int>(b.data[i]);
398 result.data[i] =
static_cast<byte_t>(val > 255 ? 255 : val);
411#if defined(__SSE4_1__) || defined(NEFORCE_SIMD_AVX2)
412 return ::_mm_adds_epu16(a, b);
413#elif defined(NEFORCE_SIMD_SSE2)
414 const ::__m128i
sum = ::_mm_add_epi16(a, b);
415 const ::__m128i
sign = ::_mm_set1_epi16(
static_cast<short>(0x8000));
416 const ::__m128i overflow = ::_mm_cmpgt_epi16(::_mm_xor_si128(a,
sign), ::_mm_xor_si128(
sum,
sign));
417 return ::_mm_or_si128(overflow,
sum);
418#elif defined(NEFORCE_SIMD_NEON)
419 return ::vreinterpretq_u8_u16(::vqaddq_u16(::vreinterpretq_u16_u8(a), ::vreinterpretq_u16_u8(b)));
422 for (
int i = 0; i < 8; ++i) {
423 const int val =
static_cast<int>(
reinterpret_cast<const uint16_t*
>(a.data)[i]) +
424 static_cast<int>(
reinterpret_cast<const uint16_t*
>(b.data)[i]);
425 reinterpret_cast<uint16_t*
>(result.data)[i] =
static_cast<uint16_t>(val > 65535 ? 65535 : val);
438#ifdef NEFORCE_SIMD_SSE2
439 return ::_mm_subs_epi8(a, b);
440#elif defined(NEFORCE_SIMD_NEON)
441 return ::vreinterpretq_u8_s8(::vqsubq_s8(::vreinterpretq_s8_u8(a), ::vreinterpretq_s8_u8(b)));
444 for (
int i = 0; i < 16; ++i) {
445 const int val =
static_cast<int8_t>(a.data[i]) -
static_cast<int8_t>(b.data[i]);
447 result.data[i] = 127;
448 }
else if (val < -128) {
449 result.data[i] = 128;
451 result.data[i] =
static_cast<byte_t>(
static_cast<int8_t>(val));
465#ifdef NEFORCE_SIMD_SSE2
466 return ::_mm_subs_epi16(a, b);
467#elif defined(NEFORCE_SIMD_NEON)
468 return ::vreinterpretq_u8_s16(::vqsubq_s16(::vreinterpretq_s16_u8(a), ::vreinterpretq_s16_u8(b)));
470 const auto* sa =
reinterpret_cast<const int16_t*
>(a.data);
471 const auto* sb =
reinterpret_cast<const int16_t*
>(b.data);
473 auto* rd =
reinterpret_cast<int16_t*
>(result.data);
474 for (
int i = 0; i < 8; ++i) {
475 const int val = sa[i] - sb[i];
478 }
else if (val < -32768) {
481 rd[i] =
static_cast<int16_t>(val);
495#ifdef NEFORCE_SIMD_SSE2
496 return ::_mm_subs_epu8(a, b);
497#elif defined(NEFORCE_SIMD_NEON)
498 return ::vqsubq_u8(a, b);
501 for (
int i = 0; i < 16; ++i) {
502 const int val =
static_cast<int>(a.data[i]) -
static_cast<int>(b.data[i]);
503 result.data[i] =
static_cast<byte_t>(val < 0 ? 0 : val);
516#if defined(__SSE4_1__) || defined(NEFORCE_SIMD_AVX2)
517 return ::_mm_subs_epu16(a, b);
518#elif defined(NEFORCE_SIMD_SSE2)
519 const ::__m128i sub = ::_mm_sub_epi16(a, b);
520 const ::__m128i
sign = ::_mm_set1_epi16(
static_cast<short>(0x8000));
521 const ::__m128i underflow = ::_mm_cmpgt_epi16(::_mm_xor_si128(b,
sign), ::_mm_xor_si128(a,
sign));
522 return ::_mm_andnot_si128(underflow, sub);
523#elif defined(NEFORCE_SIMD_NEON)
524 return ::vreinterpretq_u8_u16(::vqsubq_u16(::vreinterpretq_u16_u8(a), ::vreinterpretq_u16_u8(b)));
527 for (
int i = 0; i < 8; ++i) {
528 const int val =
static_cast<int>(
reinterpret_cast<const uint16_t*
>(a.data)[i]) -
529 static_cast<int>(
reinterpret_cast<const uint16_t*
>(b.data)[i]);
530 reinterpret_cast<uint16_t*
>(result.data)[i] =
static_cast<uint16_t>(val < 0 ? 0 : val);
543#if defined(__SSSE3__) || defined(NEFORCE_SIMD_AVX2)
544 return ::_mm_abs_epi8(v);
545#elif defined(NEFORCE_SIMD_SSE2)
546 const ::__m128i mask = ::_mm_cmpgt_epi8(::_mm_setzero_si128(), v);
547 return ::_mm_or_si128(::_mm_and_si128(mask, ::_mm_sub_epi8(::_mm_setzero_si128(), v)), ::_mm_andnot_si128(mask, v));
548#elif defined(NEFORCE_SIMD_NEON)
549 return ::vreinterpretq_u8_s8(::vabsq_s8(::vreinterpretq_s8_u8(v)));
552 for (
int i = 0; i < 16; ++i) {
553 const auto val =
static_cast<int8_t>(v.data[i]);
556 val < 0 ? static_cast<byte_t>(
static_cast<int8_t>(-
static_cast<unsigned>(
static_cast<uint8_t>(val))))
557 :
static_cast<byte_t>(val);
570#if defined(__SSSE3__) || defined(NEFORCE_SIMD_AVX2)
571 return ::_mm_abs_epi16(v);
572#elif defined(NEFORCE_SIMD_SSE2)
573 const ::__m128i mask = ::_mm_cmpgt_epi16(::_mm_setzero_si128(), v);
574 const ::__m128i neg = ::_mm_sub_epi16(::_mm_setzero_si128(), v);
575 return ::_mm_or_si128(::_mm_and_si128(mask, neg), ::_mm_andnot_si128(mask, v));
576#elif defined(NEFORCE_SIMD_NEON)
577 return ::vreinterpretq_u8_s16(::vabsq_s16(::vreinterpretq_s16_u8(v)));
579 const auto* sv =
reinterpret_cast<const int16_t*
>(v.data);
581 auto* rd =
reinterpret_cast<int16_t*
>(result.data);
582 for (
int i = 0; i < 8; ++i) {
584 rd[i] = val < 0 ? static_cast<int16_t>(-
static_cast<int>(
static_cast<uint16_t>(val))) : val;
597#if defined(__SSSE3__) || defined(NEFORCE_SIMD_AVX2)
598 return ::_mm_abs_epi32(v);
599#elif defined(NEFORCE_SIMD_SSE2)
600 const ::__m128i mask = ::_mm_srai_epi32(v, 31);
601 const ::__m128i flipped = ::_mm_xor_si128(v, mask);
602 return ::_mm_sub_epi32(flipped, mask);
603#elif defined(NEFORCE_SIMD_NEON)
604 return ::vreinterpretq_u8_s32(::vabsq_s32(::vreinterpretq_s32_u8(v)));
606 const auto* sv =
reinterpret_cast<const int32_t*
>(v.data);
608 auto* rd =
reinterpret_cast<int32_t*
>(result.data);
609 for (
int i = 0; i < 4; ++i) {
611 rd[i] = val < 0 ? static_cast<int32_t>(-
static_cast<int64_t>(
static_cast<uint32_t>(val))) : val;
624#if defined(__SSE4_1__) || defined(NEFORCE_SIMD_AVX2)
625 return ::_mm_min_epi8(a, b);
626#elif defined(NEFORCE_SIMD_SSE2)
627 const ::__m128i
sign = ::_mm_set1_epi8(
static_cast<char>(0x80));
628 const ::__m128i flipped_a = ::_mm_xor_si128(a,
sign);
629 const ::__m128i flipped_b = ::_mm_xor_si128(b,
sign);
630 return ::_mm_xor_si128(::_mm_min_epu8(flipped_a, flipped_b),
sign);
631#elif defined(NEFORCE_SIMD_NEON)
632 return ::vreinterpretq_u8_s8(::vminq_s8(::vreinterpretq_s8_u8(a), ::vreinterpretq_s8_u8(b)));
635 for (
int i = 0; i < 16; ++i) {
636 const auto va =
static_cast<int8_t>(a.data[i]);
637 const auto vb =
static_cast<int8_t>(b.data[i]);
638 result.data[i] =
static_cast<byte_t>(va < vb ? va : vb);
651#ifdef NEFORCE_SIMD_SSE2
652 return ::_mm_min_epi16(a, b);
653#elif defined(NEFORCE_SIMD_NEON)
654 return ::vreinterpretq_u8_s16(::vminq_s16(::vreinterpretq_s16_u8(a), ::vreinterpretq_s16_u8(b)));
656 const auto* sa =
reinterpret_cast<const int16_t*
>(a.data);
657 const auto* sb =
reinterpret_cast<const int16_t*
>(b.data);
659 auto* rd =
reinterpret_cast<int16_t*
>(result.data);
660 for (
int i = 0; i < 8; ++i) {
661 rd[i] = sa[i] < sb[i] ? sa[i] : sb[i];
674#if defined(__SSE4_1__) || defined(NEFORCE_SIMD_AVX2)
675 return ::_mm_min_epi32(a, b);
676#elif defined(NEFORCE_SIMD_SSE2)
677 const ::__m128i mask = ::_mm_cmpgt_epi32(b, a);
678 return ::_mm_or_si128(::_mm_and_si128(mask, a), ::_mm_andnot_si128(mask, b));
679#elif defined(NEFORCE_SIMD_NEON)
680 return ::vreinterpretq_u8_s32(::vminq_s32(::vreinterpretq_s32_u8(a), ::vreinterpretq_s32_u8(b)));
682 const auto* sa =
reinterpret_cast<const int32_t*
>(a.data);
683 const auto* sb =
reinterpret_cast<const int32_t*
>(b.data);
685 auto* rd =
reinterpret_cast<int32_t*
>(result.data);
686 for (
int i = 0; i < 4; ++i) {
687 rd[i] = sa[i] < sb[i] ? sa[i] : sb[i];
700#ifdef NEFORCE_SIMD_SSE2
701 return ::_mm_min_epu8(a, b);
702#elif defined(NEFORCE_SIMD_NEON)
703 return ::vminq_u8(a, b);
706 for (
int i = 0; i < 16; ++i) {
707 result.data[i] = a.data[i] < b.data[i] ? a.data[i] : b.data[i];
720#if defined(__SSE4_1__) || defined(NEFORCE_SIMD_AVX2)
721 return ::_mm_min_epu16(a, b);
722#elif defined(NEFORCE_SIMD_SSE2)
723 const ::__m128i offset = ::_mm_set1_epi16(
static_cast<short>(0x8000));
724 const ::__m128i mask = ::_mm_cmpgt_epi16(::_mm_sub_epi16(b, offset), ::_mm_sub_epi16(a, offset));
725 return ::_mm_or_si128(::_mm_and_si128(mask, a), ::_mm_andnot_si128(mask, b));
726#elif defined(NEFORCE_SIMD_NEON)
727 return ::vreinterpretq_u8_u16(::vminq_u16(::vreinterpretq_u16_u8(a), ::vreinterpretq_u16_u8(b)));
729 const auto* ua =
reinterpret_cast<const uint16_t*
>(a.data);
730 const auto* ub =
reinterpret_cast<const uint16_t*
>(b.data);
732 auto* rd =
reinterpret_cast<uint16_t*
>(result.data);
733 for (
int i = 0; i < 8; ++i) {
734 rd[i] = ua[i] < ub[i] ? ua[i] : ub[i];
747#if defined(__SSE4_1__) || defined(NEFORCE_SIMD_AVX2)
748 return ::_mm_min_epu32(a, b);
749#elif defined(NEFORCE_SIMD_SSE2)
750 const ::__m128i
sign = ::_mm_set1_epi32(
static_cast<int>(0x80000000));
751 const ::__m128i mask = ::_mm_cmpgt_epi32(::_mm_xor_si128(b,
sign), ::_mm_xor_si128(a,
sign));
752 return ::_mm_or_si128(::_mm_and_si128(mask, a), ::_mm_andnot_si128(mask, b));
753#elif defined(NEFORCE_SIMD_NEON)
754 return ::vreinterpretq_u8_u32(::vminq_u32(::vreinterpretq_u32_u8(a), ::vreinterpretq_u32_u8(b)));
756 const auto* ua =
reinterpret_cast<const uint32_t*
>(a.data);
757 const auto* ub =
reinterpret_cast<const uint32_t*
>(b.data);
759 auto* rd =
reinterpret_cast<uint32_t*
>(result.data);
760 for (
int i = 0; i < 4; ++i) {
761 rd[i] = ua[i] < ub[i] ? ua[i] : ub[i];
774#if defined(__SSE4_1__) || defined(NEFORCE_SIMD_AVX2)
775 return ::_mm_max_epi8(a, b);
776#elif defined(NEFORCE_SIMD_SSE2)
777 const ::__m128i
sign = ::_mm_set1_epi8(
static_cast<char>(0x80));
778 return ::_mm_xor_si128(::_mm_max_epu8(::_mm_xor_si128(a,
sign), ::_mm_xor_si128(b,
sign)),
sign);
779#elif defined(NEFORCE_SIMD_NEON)
780 return ::vreinterpretq_u8_s8(::vmaxq_s8(::vreinterpretq_s8_u8(a), ::vreinterpretq_s8_u8(b)));
783 for (
int i = 0; i < 16; ++i) {
784 const auto va =
static_cast<int8_t>(a.data[i]);
785 const auto vb =
static_cast<int8_t>(b.data[i]);
786 result.data[i] =
static_cast<byte_t>(va > vb ? va : vb);
799#ifdef NEFORCE_SIMD_SSE2
800 return ::_mm_max_epi16(a, b);
801#elif defined(NEFORCE_SIMD_NEON)
802 return ::vreinterpretq_u8_s16(::vmaxq_s16(::vreinterpretq_s16_u8(a), ::vreinterpretq_s16_u8(b)));
804 const auto* sa =
reinterpret_cast<const int16_t*
>(a.data);
805 const auto* sb =
reinterpret_cast<const int16_t*
>(b.data);
807 auto* rd =
reinterpret_cast<int16_t*
>(result.data);
808 for (
int i = 0; i < 8; ++i) {
809 rd[i] = sa[i] > sb[i] ? sa[i] : sb[i];
822#if defined(__SSE4_1__) || defined(NEFORCE_SIMD_AVX2)
823 return ::_mm_max_epi32(a, b);
824#elif defined(NEFORCE_SIMD_SSE2)
825 const ::__m128i mask = ::_mm_cmpgt_epi32(a, b);
826 return ::_mm_or_si128(::_mm_and_si128(mask, a), ::_mm_andnot_si128(mask, b));
827#elif defined(NEFORCE_SIMD_NEON)
828 return ::vreinterpretq_u8_s32(::vmaxq_s32(::vreinterpretq_s32_u8(a), ::vreinterpretq_s32_u8(b)));
830 const auto* sa =
reinterpret_cast<const int32_t*
>(a.data);
831 const auto* sb =
reinterpret_cast<const int32_t*
>(b.data);
833 auto* rd =
reinterpret_cast<int32_t*
>(result.data);
834 for (
int i = 0; i < 4; ++i) {
835 rd[i] = sa[i] > sb[i] ? sa[i] : sb[i];
848#ifdef NEFORCE_SIMD_SSE2
849 return ::_mm_max_epu8(a, b);
850#elif defined(NEFORCE_SIMD_NEON)
851 return ::vmaxq_u8(a, b);
854 for (
int i = 0; i < 16; ++i) {
855 result.data[i] = a.data[i] > b.data[i] ? a.data[i] : b.data[i];
868#if defined(__SSE4_1__) || defined(NEFORCE_SIMD_AVX2)
869 return ::_mm_max_epu16(a, b);
870#elif defined(NEFORCE_SIMD_SSE2)
871 const ::__m128i mask = ::_mm_cmpgt_epi16(a, b);
872 const ::__m128i overflow = ::_mm_cmpgt_epi16(::_mm_xor_si128(a, ::_mm_set1_epi16(
static_cast<short>(0x8000))),
873 ::_mm_xor_si128(b, ::_mm_set1_epi16(
static_cast<short>(0x8000))));
874 return ::_mm_or_si128(::_mm_and_si128(overflow, a), ::_mm_andnot_si128(overflow, b));
875#elif defined(NEFORCE_SIMD_NEON)
876 return ::vreinterpretq_u8_u16(::vmaxq_u16(::vreinterpretq_u16_u8(a), ::vreinterpretq_u16_u8(b)));
878 const auto* ua =
reinterpret_cast<const uint16_t*
>(a.data);
879 const auto* ub =
reinterpret_cast<const uint16_t*
>(b.data);
881 auto* rd =
reinterpret_cast<uint16_t*
>(result.data);
882 for (
int i = 0; i < 8; ++i) {
883 rd[i] = ua[i] > ub[i] ? ua[i] : ub[i];
896#if defined(__SSE4_1__) || defined(NEFORCE_SIMD_AVX2)
897 return ::_mm_max_epu32(a, b);
898#elif defined(NEFORCE_SIMD_SSE2)
899 const ::__m128i
sign = ::_mm_set1_epi32(
static_cast<int>(0x80000000));
900 const ::__m128i mask = ::_mm_cmpgt_epi32(::_mm_xor_si128(a,
sign), ::_mm_xor_si128(b,
sign));
901 return ::_mm_or_si128(::_mm_and_si128(mask, a), ::_mm_andnot_si128(mask, b));
902#elif defined(NEFORCE_SIMD_NEON)
903 return ::vreinterpretq_u8_u32(::vmaxq_u32(::vreinterpretq_u32_u8(a), ::vreinterpretq_u32_u8(b)));
905 const auto* ua =
reinterpret_cast<const uint32_t*
>(a.data);
906 const auto* ub =
reinterpret_cast<const uint32_t*
>(b.data);
908 auto* rd =
reinterpret_cast<uint32_t*
>(result.data);
909 for (
int i = 0; i < 4; ++i) {
910 rd[i] = ua[i] > ub[i] ? ua[i] : ub[i];
923#ifdef NEFORCE_SIMD_SSE2
924 return ::_mm_avg_epu8(a, b);
925#elif defined(NEFORCE_SIMD_NEON)
926 return ::vrhaddq_u8(a, b);
929 for (
int i = 0; i < 16; ++i) {
930 result.data[i] =
static_cast<byte_t>((
static_cast<int>(a.data[i]) +
static_cast<int>(b.data[i]) + 1) >> 1);
943#ifdef NEFORCE_SIMD_SSE2
944 return ::_mm_avg_epu16(a, b);
945#elif defined(NEFORCE_SIMD_NEON)
946 return ::vreinterpretq_u8_u16(::vrhaddq_u16(::vreinterpretq_u16_u8(a), ::vreinterpretq_u16_u8(b)));
948 const auto* ua =
reinterpret_cast<const uint16_t*
>(a.data);
949 const auto* ub =
reinterpret_cast<const uint16_t*
>(b.data);
951 auto* rd =
reinterpret_cast<uint16_t*
>(result.data);
952 for (
int i = 0; i < 8; ++i) {
953 rd[i] =
static_cast<uint16_t>((
static_cast<int>(ua[i]) +
static_cast<int>(ub[i]) + 1) >> 1);
962NEFORCE_END_NAMESPACE__
unsigned char byte_t
字节类型,定义为无符号字符
unsigned int uint32_t
32位无符号整数类型
unsigned char uint8_t
8位无符号整数类型
unsigned short uint16_t
16位无符号整数类型
signed char int8_t
8位有符号整数类型
constexpr const T & sum(const T &x) noexcept
单参数求和
constexpr int sign(const T &value) noexcept
获取数值的符号
vec128_t min_u32(vec128_t a, vec128_t b) noexcept
4 路 32-bit 无符号整数最小值
::__m128i vec128_t
128-bit 整型向量(16×i8 / 8×i16 / 4×i32 / 2×i64)
vec128_t saturated_add_i16(vec128_t a, vec128_t b) noexcept
8 路 16-bit 有符号饱和加法
vec128_t max_u32(vec128_t a, vec128_t b) noexcept
4 路 32-bit 无符号整数最大值
vec128_t saturated_sub_u16(vec128_t a, vec128_t b) noexcept
8 路 16-bit 无符号饱和减法
vec128_t abs_i16(vec128_t v) noexcept
8 路 16-bit 有符号整数绝对值
vec128_t sub_i32(vec128_t a, vec128_t b) noexcept
4 路 32-bit 有符号整数减法
vec128_t saturated_sub_i8(vec128_t a, vec128_t b) noexcept
16 路 8-bit 有符号饱和减法
vec128_t min_i8(vec128_t a, vec128_t b) noexcept
16 路 8-bit 有符号整数最小值
vec128_t add_i16(vec128_t a, vec128_t b) noexcept
8 路 16-bit 有符号整数加法
vec128_t abs_i8(vec128_t v) noexcept
16 路 8-bit 有符号整数绝对值
vec128_t sub_i8(vec128_t a, vec128_t b) noexcept
16 路 8-bit 有符号整数减法
vec128_t mullo_i32(vec128_t a, vec128_t b) noexcept
4 路 32-bit 整数乘法(取低半部分)
vec128_t min_i32(vec128_t a, vec128_t b) noexcept
4 路 32-bit 有符号整数最小值
vec128_t max_i32(vec128_t a, vec128_t b) noexcept
4 路 32-bit 有符号整数最大值
vec128_t add_i32(vec128_t a, vec128_t b) noexcept
4 路 32-bit 有符号整数加法
vec128_t add_i64(vec128_t a, vec128_t b) noexcept
2 路 64-bit 有符号整数加法
vec128_t min_u16(vec128_t a, vec128_t b) noexcept
8 路 16-bit 无符号整数最小值
vec128_t sub_i64(vec128_t a, vec128_t b) noexcept
2 路 64-bit 有符号整数减法
vec128_t saturated_sub_u8(vec128_t a, vec128_t b) noexcept
16 路 8-bit 无符号饱和减法
vec128_t mulhi_i16(vec128_t a, vec128_t b) noexcept
8 路 16-bit 有符号整数乘法(取高半部分)
vec128_t saturated_add_u8(vec128_t a, vec128_t b) noexcept
16 路 8-bit 无符号饱和加法
vec128_t add_i8(vec128_t a, vec128_t b) noexcept
16 路 8-bit 有符号整数加法
vec128_t max_i16(vec128_t a, vec128_t b) noexcept
8 路 16-bit 有符号整数最大值
vec128_t abs_i32(vec128_t v) noexcept
4 路 32-bit 有符号整数绝对值
vec128_t saturated_sub_i16(vec128_t a, vec128_t b) noexcept
8 路 16-bit 有符号饱和减法
vec128_t sub_i16(vec128_t a, vec128_t b) noexcept
8 路 16-bit 有符号整数减法
vec128_t min_i16(vec128_t a, vec128_t b) noexcept
8 路 16-bit 有符号整数最小值
vec128_t madds_i8x16(vec128_t a, vec128_t b) noexcept
有符号 8-bit 相邻对乘加:将相邻 i8 相乘后累加为 i16
vec128_t max_u16(vec128_t a, vec128_t b) noexcept
8 路 16-bit 无符号整数最大值
vec128_t avg_u8(vec128_t a, vec128_t b) noexcept
16 路 8-bit 无符号整数平均值(向偶数舍入)
vec128_t mullo_i16(vec128_t a, vec128_t b) noexcept
8 路 16-bit 整数乘法(取低半部分)
vec128_t saturated_add_i8(vec128_t a, vec128_t b) noexcept
16 路 8-bit 有符号饱和加法
vec128_t min_u8(vec128_t a, vec128_t b) noexcept
16 路 8-bit 无符号整数最小值
vec128_t avg_u16(vec128_t a, vec128_t b) noexcept
8 路 16-bit 无符号整数平均值(向偶数舍入)
vec128_t max_u8(vec128_t a, vec128_t b) noexcept
16 路 8-bit 无符号整数最大值
vec128_t saturated_add_u16(vec128_t a, vec128_t b) noexcept
8 路 16-bit 无符号饱和加法
vec128_t max_i8(vec128_t a, vec128_t b) noexcept
16 路 8-bit 有符号整数最大值