8#include <rapidfuzz/details/intrinsics.hpp>
19class native_simd<uint64_t> {
21 static constexpr int alignment = 16;
22 static const int size = 2;
25 native_simd() noexcept
28 native_simd(__m128i val) noexcept : xmm(val)
31 native_simd(uint64_t a)
noexcept
33 xmm = _mm_set1_epi64x(
static_cast<int64_t
>(a));
36 native_simd(
const uint64_t* p)
noexcept
41 operator __m128i() const noexcept
46 native_simd load(
const uint64_t* p)
noexcept
48 xmm = _mm_set_epi64x(
static_cast<int64_t
>(p[1]),
static_cast<int64_t
>(p[0]));
52 void store(uint64_t* p)
const noexcept
54 _mm_store_si128(
reinterpret_cast<__m128i*
>(p), xmm);
57 native_simd operator+(
const native_simd b)
const noexcept
59 return _mm_add_epi64(xmm, b);
62 native_simd& operator+=(
const native_simd b)
noexcept
64 xmm = _mm_add_epi64(xmm, b);
68 native_simd operator-(
const native_simd b)
const noexcept
70 return _mm_sub_epi64(xmm, b);
73 native_simd operator-() const noexcept
75 return _mm_sub_epi64(_mm_setzero_si128(), xmm);
78 native_simd& operator-=(
const native_simd b)
noexcept
80 xmm = _mm_sub_epi64(xmm, b);
86class native_simd<uint32_t> {
88 static constexpr int alignment = 16;
89 static const int size = 4;
92 native_simd() noexcept
95 native_simd(__m128i val) noexcept : xmm(val)
98 native_simd(uint32_t a)
noexcept
100 xmm = _mm_set1_epi32(
static_cast<int>(a));
103 native_simd(
const uint64_t* p)
noexcept
108 operator __m128i() const noexcept
113 native_simd load(
const uint64_t* p)
noexcept
115 xmm = _mm_set_epi64x(
static_cast<int64_t
>(p[1]),
static_cast<int64_t
>(p[0]));
119 void store(uint32_t* p)
const noexcept
121 _mm_store_si128(
reinterpret_cast<__m128i*
>(p), xmm);
124 native_simd operator+(
const native_simd b)
const noexcept
126 return _mm_add_epi32(xmm, b);
129 native_simd& operator+=(
const native_simd b)
noexcept
131 xmm = _mm_add_epi32(xmm, b);
135 native_simd operator-(
const native_simd b)
const noexcept
137 return _mm_sub_epi32(xmm, b);
140 native_simd operator-() const noexcept
142 return _mm_sub_epi32(_mm_setzero_si128(), xmm);
145 native_simd& operator-=(
const native_simd b)
noexcept
147 xmm = _mm_sub_epi32(xmm, b);
153class native_simd<uint16_t> {
155 static constexpr int alignment = 16;
156 static const int size = 8;
159 native_simd() noexcept
162 native_simd(__m128i val) noexcept : xmm(val)
165 native_simd(uint16_t a)
noexcept
167 xmm = _mm_set1_epi16(
static_cast<short>(a));
170 native_simd(
const uint64_t* p)
noexcept
175 operator __m128i() const noexcept
180 native_simd load(
const uint64_t* p)
noexcept
182 xmm = _mm_set_epi64x(
static_cast<int64_t
>(p[1]),
static_cast<int64_t
>(p[0]));
186 void store(uint16_t* p)
const noexcept
188 _mm_store_si128(
reinterpret_cast<__m128i*
>(p), xmm);
191 native_simd operator+(
const native_simd b)
const noexcept
193 return _mm_add_epi16(xmm, b);
196 native_simd& operator+=(
const native_simd b)
noexcept
198 xmm = _mm_add_epi16(xmm, b);
202 native_simd operator-(
const native_simd b)
const noexcept
204 return _mm_sub_epi16(xmm, b);
207 native_simd operator-() const noexcept
209 return _mm_sub_epi16(_mm_setzero_si128(), xmm);
212 native_simd& operator-=(
const native_simd b)
noexcept
214 xmm = _mm_sub_epi16(xmm, b);
220class native_simd<uint8_t> {
222 static constexpr int alignment = 16;
223 static const int size = 16;
226 native_simd() noexcept
229 native_simd(__m128i val) noexcept : xmm(val)
232 native_simd(uint8_t a)
noexcept
234 xmm = _mm_set1_epi8(
static_cast<char>(a));
237 native_simd(
const uint64_t* p)
noexcept
242 operator __m128i() const noexcept
247 native_simd load(
const uint64_t* p)
noexcept
249 xmm = _mm_set_epi64x(
static_cast<int64_t
>(p[1]),
static_cast<int64_t
>(p[0]));
253 void store(uint8_t* p)
const noexcept
255 _mm_store_si128(
reinterpret_cast<__m128i*
>(p), xmm);
258 native_simd operator+(
const native_simd b)
const noexcept
260 return _mm_add_epi8(xmm, b);
263 native_simd& operator+=(
const native_simd b)
noexcept
265 xmm = _mm_add_epi8(xmm, b);
269 native_simd operator-(
const native_simd b)
const noexcept
271 return _mm_sub_epi8(xmm, b);
274 native_simd operator-() const noexcept
276 return _mm_sub_epi8(_mm_setzero_si128(), xmm);
279 native_simd& operator-=(
const native_simd b)
noexcept
281 xmm = _mm_sub_epi8(xmm, b);
287std::ostream& operator<<(std::ostream& os,
const native_simd<T>& a)
289 alignas(native_simd<T>::alignment) std::array<T, native_simd<T>::size> res;
292 for (
size_t i = res.size() - 1; i != 0; i--)
293 os << std::bitset<std::numeric_limits<T>::digits>(res[i]) <<
"|";
295 os << std::bitset<std::numeric_limits<T>::digits>(res[0]);
300__m128i hadd_impl(__m128i x)
noexcept;
303inline __m128i hadd_impl<uint8_t>(__m128i x)
noexcept
309inline __m128i hadd_impl<uint16_t>(__m128i x)
noexcept
311 const __m128i mask = _mm_set1_epi16(0x001f);
312 __m128i y = _mm_srli_si128(x, 1);
313 x = _mm_add_epi16(x, y);
314 return _mm_and_si128(x, mask);
318inline __m128i hadd_impl<uint32_t>(__m128i x)
noexcept
320 const __m128i mask = _mm_set1_epi32(0x0000003f);
321 x = hadd_impl<uint16_t>(x);
322 __m128i y = _mm_srli_si128(x, 2);
323 x = _mm_add_epi32(x, y);
324 return _mm_and_si128(x, mask);
328inline __m128i hadd_impl<uint64_t>(__m128i x)
noexcept
330 return _mm_sad_epu8(x, _mm_setzero_si128());
334native_simd<T> popcount_impl(
const native_simd<T>& v)
noexcept
336 const __m128i m1 = _mm_set1_epi8(0x55);
337 const __m128i m2 = _mm_set1_epi8(0x33);
338 const __m128i m3 = _mm_set1_epi8(0x0F);
344 y = _mm_srli_epi64(x, 1);
345 y = _mm_and_si128(y, m1);
346 x = _mm_subs_epu8(x, y);
349 y = _mm_srli_epi64(x, 2);
350 y = _mm_and_si128(y, m2);
351 x = _mm_and_si128(x, m2);
352 x = _mm_adds_epu8(x, y);
355 y = _mm_srli_epi64(x, 4);
356 x = _mm_adds_epu8(x, y);
357 x = _mm_and_si128(x, m3);
368 return hadd_impl<T>(x);
372std::array<T, native_simd<T>::size> popcount(
const native_simd<T>& a)
noexcept
374 alignas(native_simd<T>::alignment) std::array<T, native_simd<T>::size> res;
375 popcount_impl(a).store(&res[0]);
381native_simd<T> andnot(
const native_simd<T>& a,
const native_simd<T>& b)
383 return _mm_andnot_si128(b, a);
386static inline native_simd<uint8_t> operator==(
const native_simd<uint8_t>& a,
387 const native_simd<uint8_t>& b)
noexcept
389 return _mm_cmpeq_epi8(a, b);
392static inline native_simd<uint16_t> operator==(
const native_simd<uint16_t>& a,
393 const native_simd<uint16_t>& b)
noexcept
395 return _mm_cmpeq_epi16(a, b);
398static inline native_simd<uint32_t> operator==(
const native_simd<uint32_t>& a,
399 const native_simd<uint32_t>& b)
noexcept
401 return _mm_cmpeq_epi32(a, b);
404static inline native_simd<uint64_t> operator==(
const native_simd<uint64_t>& a,
405 const native_simd<uint64_t>& b)
noexcept
408 __m128i com32 = _mm_cmpeq_epi32(a, b);
409 __m128i com32s = _mm_shuffle_epi32(com32, 0xB1);
410 __m128i test = _mm_and_si128(com32, com32s);
411 __m128i teste = _mm_srai_epi32(test, 31);
412 __m128i testee = _mm_shuffle_epi32(teste, 0xF5);
417static inline native_simd<T> operator!=(
const native_simd<T>& a,
const native_simd<T>& b)
noexcept
422static inline native_simd<uint8_t> operator<<(
const native_simd<uint8_t>& a,
int b)
noexcept
424 char mask =
static_cast<char>(0xFF >> b);
425 __m128i am = _mm_and_si128(a, _mm_set1_epi8(mask));
426 return _mm_slli_epi16(am, b);
429static inline native_simd<uint16_t> operator<<(
const native_simd<uint16_t>& a,
int b)
noexcept
431 return _mm_slli_epi16(a, b);
434static inline native_simd<uint32_t> operator<<(
const native_simd<uint32_t>& a,
int b)
noexcept
436 return _mm_slli_epi32(a, b);
439static inline native_simd<uint64_t> operator<<(
const native_simd<uint64_t>& a,
int b)
noexcept
441 return _mm_slli_epi64(a, b);
444static inline native_simd<uint8_t> operator>>(
const native_simd<uint8_t>& a,
int b)
noexcept
446 char mask =
static_cast<char>(0xFF << b);
447 __m128i am = _mm_and_si128(a, _mm_set1_epi8(mask));
448 return _mm_srli_epi16(am, b);
451static inline native_simd<uint16_t> operator>>(
const native_simd<uint16_t>& a,
int b)
noexcept
453 return _mm_srli_epi16(a, b);
456static inline native_simd<uint32_t> operator>>(
const native_simd<uint32_t>& a,
int b)
noexcept
458 return _mm_srli_epi32(a, b);
461static inline native_simd<uint64_t> operator>>(
const native_simd<uint64_t>& a,
int b)
noexcept
463 return _mm_srli_epi64(a, b);
467native_simd<T> operator&(
const native_simd<T>& a,
const native_simd<T>& b)
noexcept
469 return _mm_and_si128(a, b);
473native_simd<T> operator&=(native_simd<T>& a,
const native_simd<T>& b)
noexcept
480native_simd<T> operator|(
const native_simd<T>& a,
const native_simd<T>& b)
noexcept
482 return _mm_or_si128(a, b);
486native_simd<T> operator|=(native_simd<T>& a,
const native_simd<T>& b)
noexcept
493native_simd<T> operator^(
const native_simd<T>& a,
const native_simd<T>& b)
noexcept
495 return _mm_xor_si128(a, b);
499native_simd<T> operator^=(native_simd<T>& a,
const native_simd<T>& b)
noexcept
506native_simd<T> operator~(
const native_simd<T>& a)
noexcept
508 return _mm_xor_si128(a, _mm_set1_epi32(-1));
512static inline native_simd<uint8_t> operator>=(
const native_simd<uint8_t>& a,
513 const native_simd<uint8_t>& b)
noexcept
515 return _mm_cmpeq_epi8(_mm_max_epu8(a, b), a);
518static inline native_simd<uint16_t> operator>=(
const native_simd<uint16_t>& a,
519 const native_simd<uint16_t>& b)
noexcept
523 return _mm_cmpeq_epi16(_mm_max_epu16(a, b), a);
526 __m128i s = _mm_subs_epu16(b, a);
527 return _mm_cmpeq_epi16(s, _mm_setzero_si128());
530static inline native_simd<uint64_t> operator>(
const native_simd<uint64_t>& a,
531 const native_simd<uint64_t>& b)
noexcept;
532static inline native_simd<uint32_t> operator>(
const native_simd<uint32_t>& a,
533 const native_simd<uint32_t>& b)
noexcept;
535static inline native_simd<uint32_t> operator>=(
const native_simd<uint32_t>& a,
536 const native_simd<uint32_t>& b)
noexcept
540 return (Vec4ib)_mm_cmpeq_epi32(_mm_max_epu32(a, b), a);
546static inline native_simd<uint64_t> operator>=(
const native_simd<uint64_t>& a,
547 const native_simd<uint64_t>& b)
noexcept
553static inline native_simd<T> operator<=(
const native_simd<T>& a,
const native_simd<T>& b)
noexcept
558static inline native_simd<uint8_t> operator>(
const native_simd<uint8_t>& a,
559 const native_simd<uint8_t>& b)
noexcept
564static inline native_simd<uint16_t> operator>(
const native_simd<uint16_t>& a,
565 const native_simd<uint16_t>& b)
noexcept
570static inline native_simd<uint32_t> operator>(
const native_simd<uint32_t>& a,
571 const native_simd<uint32_t>& b)
noexcept
573 __m128i signbit = _mm_set1_epi32(
static_cast<int32_t
>(0x80000000));
574 __m128i a1 = _mm_xor_si128(a, signbit);
575 __m128i b1 = _mm_xor_si128(b, signbit);
576 return _mm_cmpgt_epi32(a1, b1);
579static inline native_simd<uint64_t> operator>(
const native_simd<uint64_t>& a,
580 const native_simd<uint64_t>& b)
noexcept
582 __m128i sign32 = _mm_set1_epi32(
static_cast<int32_t
>(0x80000000));
583 __m128i aflip = _mm_xor_si128(a, sign32);
584 __m128i bflip = _mm_xor_si128(b, sign32);
585 __m128i equal = _mm_cmpeq_epi32(a, b);
586 __m128i bigger = _mm_cmpgt_epi32(aflip, bflip);
587 __m128i biggerl = _mm_shuffle_epi32(bigger, 0xA0);
588 __m128i eqbig = _mm_and_si128(equal, biggerl);
589 __m128i hibig = _mm_or_si128(bigger, eqbig);
590 __m128i big = _mm_shuffle_epi32(hibig, 0xF5);
595static inline native_simd<T> operator<(
const native_simd<T>& a,
const native_simd<T>& b)
noexcept