NexusForce 1.0.0
A rigorously engineered full-stack C++ backend library.
载入中...
搜索中...
未找到
arithmetic.hpp
浏览该文件的文档.
1#ifndef NEFORCE_CORE_SIMD_ARITHMETIC_HPP__
2#define NEFORCE_CORE_SIMD_ARITHMETIC_HPP__
3
10
13NEFORCE_BEGIN_NAMESPACE__
14NEFORCE_BEGIN_SIMD__
15
20
27NEFORCE_ALWAYS_INLINE_INLINE vec128_t add_i8(vec128_t a, vec128_t b) noexcept {
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)));
32#else
33 vec128_t result;
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]));
36 }
37 return result;
38#endif
39}
40
47NEFORCE_ALWAYS_INLINE_INLINE vec128_t add_i16(vec128_t a, vec128_t b) noexcept {
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)));
52#else
53 const auto* sa = reinterpret_cast<const int16_t*>(a.data);
54 const auto* sb = reinterpret_cast<const int16_t*>(b.data);
55 vec128_t result;
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]);
59 }
60 return result;
61#endif
62}
63
70NEFORCE_ALWAYS_INLINE_INLINE vec128_t add_i32(vec128_t a, vec128_t b) noexcept {
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)));
75#else
76 const auto* sa = reinterpret_cast<const int32_t*>(a.data);
77 const auto* sb = reinterpret_cast<const int32_t*>(b.data);
78 vec128_t result;
79 auto* rd = reinterpret_cast<int32_t*>(result.data);
80 for (int i = 0; i < 4; ++i) {
81 rd[i] = sa[i] + sb[i];
82 }
83 return result;
84#endif
85}
86
93NEFORCE_ALWAYS_INLINE_INLINE vec128_t add_i64(vec128_t a, vec128_t b) noexcept {
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)));
98#else
99 const auto* sa = reinterpret_cast<const int64_t*>(a.data);
100 const auto* sb = reinterpret_cast<const int64_t*>(b.data);
101 vec128_t result;
102 auto* rd = reinterpret_cast<int64_t*>(result.data);
103 for (int i = 0; i < 2; ++i) {
104 rd[i] = sa[i] + sb[i];
105 }
106 return result;
107#endif
108}
109
116NEFORCE_ALWAYS_INLINE_INLINE vec128_t sub_i8(vec128_t a, vec128_t b) noexcept {
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)));
121#else
122 vec128_t result;
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]));
125 }
126 return result;
127#endif
128}
129
136NEFORCE_ALWAYS_INLINE_INLINE vec128_t sub_i16(vec128_t a, vec128_t b) noexcept {
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)));
141#else
142 const auto* sa = reinterpret_cast<const int16_t*>(a.data);
143 const auto* sb = reinterpret_cast<const int16_t*>(b.data);
144 vec128_t result;
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]);
148 }
149 return result;
150#endif
151}
152
159NEFORCE_ALWAYS_INLINE_INLINE vec128_t sub_i32(vec128_t a, vec128_t b) noexcept {
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)));
164#else
165 const auto* sa = reinterpret_cast<const int32_t*>(a.data);
166 const auto* sb = reinterpret_cast<const int32_t*>(b.data);
167 vec128_t result;
168 auto* rd = reinterpret_cast<int32_t*>(result.data);
169 for (int i = 0; i < 4; ++i) {
170 rd[i] = sa[i] - sb[i];
171 }
172 return result;
173#endif
174}
175
182NEFORCE_ALWAYS_INLINE_INLINE vec128_t sub_i64(vec128_t a, vec128_t b) noexcept {
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)));
187#else
188 const auto* sa = reinterpret_cast<const int64_t*>(a.data);
189 const auto* sb = reinterpret_cast<const int64_t*>(b.data);
190 vec128_t result;
191 auto* rd = reinterpret_cast<int64_t*>(result.data);
192 for (int i = 0; i < 2; ++i) {
193 rd[i] = sa[i] - sb[i];
194 }
195 return result;
196#endif
197}
198
205NEFORCE_ALWAYS_INLINE_INLINE vec128_t mullo_i16(vec128_t a, vec128_t b) noexcept {
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)));
210#else
211 const auto* sa = reinterpret_cast<const int16_t*>(a.data);
212 const auto* sb = reinterpret_cast<const int16_t*>(b.data);
213 vec128_t result;
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]);
217 }
218 return result;
219#endif
220}
221
228NEFORCE_ALWAYS_INLINE_INLINE vec128_t mullo_i32(vec128_t a, vec128_t b) noexcept {
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)));
239#else
240 const auto* sa = reinterpret_cast<const int32_t*>(a.data);
241 const auto* sb = reinterpret_cast<const int32_t*>(b.data);
242 vec128_t result;
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]);
246 }
247 return result;
248#endif
249}
250
257NEFORCE_ALWAYS_INLINE_INLINE vec128_t mulhi_i16(vec128_t a, vec128_t b) noexcept {
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));
272#else
273 const auto* sa = reinterpret_cast<const int16_t*>(a.data);
274 const auto* sb = reinterpret_cast<const int16_t*>(b.data);
275 vec128_t result;
276 auto* rd = reinterpret_cast<int16_t*>(result.data);
277 for (int i = 0; i < 8; ++i) {
278 rd[i] = static_cast<int16_t>((static_cast<int32_t>(sa[i]) * static_cast<int32_t>(sb[i])) >> 16);
279 }
280 return result;
281#endif
282}
283
291NEFORCE_ALWAYS_INLINE_INLINE vec128_t madds_i8x16(vec128_t a, vec128_t b) noexcept {
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);
297 alignas(16) int16_t result[8];
298 for (int i = 0; i < 8; ++i) {
299 result[i] = static_cast<int16_t>(static_cast<int16_t>(sa[static_cast<ptrdiff_t>(2 * i)]) *
300 static_cast<int16_t>(sb[static_cast<ptrdiff_t>(2 * i)]) +
301 static_cast<int16_t>(sa[static_cast<ptrdiff_t>(2 * i + 1)]) *
302 static_cast<int16_t>(sb[static_cast<ptrdiff_t>(2 * i + 1)]));
303 }
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));
311#else
312 const auto* sa = reinterpret_cast<const int8_t*>(a.data);
313 const auto* sb = reinterpret_cast<const int8_t*>(b.data);
314 vec128_t result;
315 auto* rd = reinterpret_cast<int16_t*>(result.data);
316 for (int i = 0; i < 8; ++i) {
317 rd[i] = static_cast<int16_t>(static_cast<int16_t>(sa[static_cast<ptrdiff_t>(2 * i)]) *
318 static_cast<int16_t>(sb[static_cast<ptrdiff_t>(2 * i)]) +
319 static_cast<int16_t>(sa[static_cast<ptrdiff_t>(2 * i + 1)]) *
320 static_cast<int16_t>(sb[static_cast<ptrdiff_t>(2 * i + 1)]));
321 }
322 return result;
323#endif
324}
325
332NEFORCE_ALWAYS_INLINE_INLINE vec128_t saturated_add_i8(vec128_t a, vec128_t b) noexcept {
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)));
337#else
338 vec128_t result;
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]);
341 if (val > 127) {
342 result.data[i] = 127;
343 } else if (val < -128) {
344 result.data[i] = 128;
345 } else {
346 result.data[i] = static_cast<byte_t>(static_cast<int8_t>(val));
347 }
348 }
349 return result;
350#endif
351}
352
359NEFORCE_ALWAYS_INLINE_INLINE vec128_t saturated_add_i16(vec128_t a, vec128_t b) noexcept {
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)));
364#else
365 const auto* sa = reinterpret_cast<const int16_t*>(a.data);
366 const auto* sb = reinterpret_cast<const int16_t*>(b.data);
367 vec128_t result;
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];
371 if (val > 32767) {
372 rd[i] = 32767;
373 } else if (val < -32768) {
374 rd[i] = -32768;
375 } else {
376 rd[i] = static_cast<int16_t>(val);
377 }
378 }
379 return result;
380#endif
381}
382
389NEFORCE_ALWAYS_INLINE_INLINE vec128_t saturated_add_u8(vec128_t a, vec128_t b) noexcept {
390#ifdef NEFORCE_SIMD_SSE2
391 return ::_mm_adds_epu8(a, b);
392#elif defined(NEFORCE_SIMD_NEON)
393 return ::vqaddq_u8(a, b);
394#else
395 vec128_t result;
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);
399 }
400 return result;
401#endif
402}
403
410NEFORCE_ALWAYS_INLINE_INLINE vec128_t saturated_add_u16(vec128_t a, vec128_t b) noexcept {
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)));
420#else
421 vec128_t result;
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);
426 }
427 return result;
428#endif
429}
430
437NEFORCE_ALWAYS_INLINE_INLINE vec128_t saturated_sub_i8(vec128_t a, vec128_t b) noexcept {
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)));
442#else
443 vec128_t result;
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]);
446 if (val > 127) {
447 result.data[i] = 127;
448 } else if (val < -128) {
449 result.data[i] = 128;
450 } else {
451 result.data[i] = static_cast<byte_t>(static_cast<int8_t>(val));
452 }
453 }
454 return result;
455#endif
456}
457
464NEFORCE_ALWAYS_INLINE_INLINE vec128_t saturated_sub_i16(vec128_t a, vec128_t b) noexcept {
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)));
469#else
470 const auto* sa = reinterpret_cast<const int16_t*>(a.data);
471 const auto* sb = reinterpret_cast<const int16_t*>(b.data);
472 vec128_t result;
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];
476 if (val > 32767) {
477 rd[i] = 32767;
478 } else if (val < -32768) {
479 rd[i] = -32768;
480 } else {
481 rd[i] = static_cast<int16_t>(val);
482 }
483 }
484 return result;
485#endif
486}
487
494NEFORCE_ALWAYS_INLINE_INLINE vec128_t saturated_sub_u8(vec128_t a, vec128_t b) noexcept {
495#ifdef NEFORCE_SIMD_SSE2
496 return ::_mm_subs_epu8(a, b);
497#elif defined(NEFORCE_SIMD_NEON)
498 return ::vqsubq_u8(a, b);
499#else
500 vec128_t result;
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);
504 }
505 return result;
506#endif
507}
508
515NEFORCE_ALWAYS_INLINE_INLINE vec128_t saturated_sub_u16(vec128_t a, vec128_t b) noexcept {
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)));
525#else
526 vec128_t result;
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);
531 }
532 return result;
533#endif
534}
535
542NEFORCE_ALWAYS_INLINE_INLINE vec128_t abs_i8(vec128_t v) noexcept {
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)));
550#else
551 vec128_t result;
552 for (int i = 0; i < 16; ++i) {
553 const auto val = static_cast<int8_t>(v.data[i]);
554 // Use unsigned negation to avoid UB, matches x86 PABSB wrap-around behavior
555 result.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);
558 }
559 return result;
560#endif
561}
562
569NEFORCE_ALWAYS_INLINE_INLINE vec128_t abs_i16(vec128_t v) noexcept {
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)));
578#else
579 const auto* sv = reinterpret_cast<const int16_t*>(v.data);
580 vec128_t result;
581 auto* rd = reinterpret_cast<int16_t*>(result.data);
582 for (int i = 0; i < 8; ++i) {
583 const int16_t val = sv[i];
584 rd[i] = val < 0 ? static_cast<int16_t>(-static_cast<int>(static_cast<uint16_t>(val))) : val;
585 }
586 return result;
587#endif
588}
589
596NEFORCE_ALWAYS_INLINE_INLINE vec128_t abs_i32(vec128_t v) noexcept {
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)));
605#else
606 const auto* sv = reinterpret_cast<const int32_t*>(v.data);
607 vec128_t result;
608 auto* rd = reinterpret_cast<int32_t*>(result.data);
609 for (int i = 0; i < 4; ++i) {
610 const int32_t val = sv[i];
611 rd[i] = val < 0 ? static_cast<int32_t>(-static_cast<int64_t>(static_cast<uint32_t>(val))) : val;
612 }
613 return result;
614#endif
615}
616
623NEFORCE_ALWAYS_INLINE_INLINE vec128_t min_i8(vec128_t a, vec128_t b) noexcept {
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)));
633#else
634 vec128_t result;
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);
639 }
640 return result;
641#endif
642}
643
650NEFORCE_ALWAYS_INLINE_INLINE vec128_t min_i16(vec128_t a, vec128_t b) noexcept {
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)));
655#else
656 const auto* sa = reinterpret_cast<const int16_t*>(a.data);
657 const auto* sb = reinterpret_cast<const int16_t*>(b.data);
658 vec128_t result;
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];
662 }
663 return result;
664#endif
665}
666
673NEFORCE_ALWAYS_INLINE_INLINE vec128_t min_i32(vec128_t a, vec128_t b) noexcept {
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)));
681#else
682 const auto* sa = reinterpret_cast<const int32_t*>(a.data);
683 const auto* sb = reinterpret_cast<const int32_t*>(b.data);
684 vec128_t result;
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];
688 }
689 return result;
690#endif
691}
692
699NEFORCE_ALWAYS_INLINE_INLINE vec128_t min_u8(vec128_t a, vec128_t b) noexcept {
700#ifdef NEFORCE_SIMD_SSE2
701 return ::_mm_min_epu8(a, b);
702#elif defined(NEFORCE_SIMD_NEON)
703 return ::vminq_u8(a, b);
704#else
705 vec128_t result;
706 for (int i = 0; i < 16; ++i) {
707 result.data[i] = a.data[i] < b.data[i] ? a.data[i] : b.data[i];
708 }
709 return result;
710#endif
711}
712
719NEFORCE_ALWAYS_INLINE_INLINE vec128_t min_u16(vec128_t a, vec128_t b) noexcept {
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)));
728#else
729 const auto* ua = reinterpret_cast<const uint16_t*>(a.data);
730 const auto* ub = reinterpret_cast<const uint16_t*>(b.data);
731 vec128_t result;
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];
735 }
736 return result;
737#endif
738}
739
746NEFORCE_ALWAYS_INLINE_INLINE vec128_t min_u32(vec128_t a, vec128_t b) noexcept {
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)));
755#else
756 const auto* ua = reinterpret_cast<const uint32_t*>(a.data);
757 const auto* ub = reinterpret_cast<const uint32_t*>(b.data);
758 vec128_t result;
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];
762 }
763 return result;
764#endif
765}
766
773NEFORCE_ALWAYS_INLINE_INLINE vec128_t max_i8(vec128_t a, vec128_t b) noexcept {
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)));
781#else
782 vec128_t result;
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);
787 }
788 return result;
789#endif
790}
791
798NEFORCE_ALWAYS_INLINE_INLINE vec128_t max_i16(vec128_t a, vec128_t b) noexcept {
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)));
803#else
804 const auto* sa = reinterpret_cast<const int16_t*>(a.data);
805 const auto* sb = reinterpret_cast<const int16_t*>(b.data);
806 vec128_t result;
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];
810 }
811 return result;
812#endif
813}
814
821NEFORCE_ALWAYS_INLINE_INLINE vec128_t max_i32(vec128_t a, vec128_t b) noexcept {
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)));
829#else
830 const auto* sa = reinterpret_cast<const int32_t*>(a.data);
831 const auto* sb = reinterpret_cast<const int32_t*>(b.data);
832 vec128_t result;
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];
836 }
837 return result;
838#endif
839}
840
847NEFORCE_ALWAYS_INLINE_INLINE vec128_t max_u8(vec128_t a, vec128_t b) noexcept {
848#ifdef NEFORCE_SIMD_SSE2
849 return ::_mm_max_epu8(a, b);
850#elif defined(NEFORCE_SIMD_NEON)
851 return ::vmaxq_u8(a, b);
852#else
853 vec128_t result;
854 for (int i = 0; i < 16; ++i) {
855 result.data[i] = a.data[i] > b.data[i] ? a.data[i] : b.data[i];
856 }
857 return result;
858#endif
859}
860
867NEFORCE_ALWAYS_INLINE_INLINE vec128_t max_u16(vec128_t a, vec128_t b) noexcept {
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)));
877#else
878 const auto* ua = reinterpret_cast<const uint16_t*>(a.data);
879 const auto* ub = reinterpret_cast<const uint16_t*>(b.data);
880 vec128_t result;
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];
884 }
885 return result;
886#endif
887}
888
895NEFORCE_ALWAYS_INLINE_INLINE vec128_t max_u32(vec128_t a, vec128_t b) noexcept {
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)));
904#else
905 const auto* ua = reinterpret_cast<const uint32_t*>(a.data);
906 const auto* ub = reinterpret_cast<const uint32_t*>(b.data);
907 vec128_t result;
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];
911 }
912 return result;
913#endif
914}
915
922NEFORCE_ALWAYS_INLINE_INLINE vec128_t avg_u8(vec128_t a, vec128_t b) noexcept {
923#ifdef NEFORCE_SIMD_SSE2
924 return ::_mm_avg_epu8(a, b);
925#elif defined(NEFORCE_SIMD_NEON)
926 return ::vrhaddq_u8(a, b);
927#else
928 vec128_t result;
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);
931 }
932 return result;
933#endif
934}
935
942NEFORCE_ALWAYS_INLINE_INLINE vec128_t avg_u16(vec128_t a, vec128_t b) noexcept {
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)));
947#else
948 const auto* ua = reinterpret_cast<const uint16_t*>(a.data);
949 const auto* ub = reinterpret_cast<const uint16_t*>(b.data);
950 vec128_t result;
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);
954 }
955 return result;
956#endif
957}
958 // SIMD
960
961NEFORCE_END_SIMD__
962NEFORCE_END_NAMESPACE__
963#endif // NEFORCE_CORE_SIMD_ARITHMETIC_HPP__
long int64_t
64位有符号整数类型
unsigned char byte_t
字节类型,定义为无符号字符
unsigned int uint32_t
32位无符号整数类型
unsigned char uint8_t
8位无符号整数类型
int int32_t
32位有符号整数类型
unsigned short uint16_t
16位无符号整数类型
short int16_t
16位有符号整数类型
signed char int8_t
8位有符号整数类型
constexpr const T & sum(const T &x) noexcept
单参数求和
constexpr int sign(const T &value) noexcept
获取数值的符号
int64_t ptrdiff_t
指针差类型
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 有符号整数最大值
数值特征
SIMD 向量类型定义