24#include <simde/x86/avx.h>
25#include <simde/x86/avx2.h>
26#include <simde/x86/sse.h>
27#include <simde/x86/sse4.1.h>
40 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
41 0xFF, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
42 0xFF, 0xFF, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02,
43 0xFF, 0xFF, 0xFF, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03,
44 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04,
45 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05,
46 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06,
47 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07,
48 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08,
49 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09,
50 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A,
51 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B,
52 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0E, 0x0D, 0x0C,
53 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0E, 0x0D,
54 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0E,
55 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F,
59 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
60 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
61 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
62 0x02, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
63 0x03, 0x02, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
64 0x04, 0x03, 0x02, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
65 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
66 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
67 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
68 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
69 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
70 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
71 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
72 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0xFF, 0xFF, 0xFF,
73 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0xFF, 0xFF,
74 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0xFF,
78 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
79 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
80 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02,
81 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03,
82 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04,
83 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05,
84 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06,
85 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07,
86 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08,
87 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09,
88 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A,
89 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B,
90 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C,
91 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D,
92 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E,
93 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F,
97 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
98 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F,
99 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E,
100 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D,
101 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C,
102 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B,
103 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A,
104 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09,
105 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08,
106 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07,
107 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06,
108 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05,
109 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04,
110 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03,
111 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02,
112 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
116using VectorOf = std::conditional_t<std::is_floating_point_v<T>, simde__m128, simde__m128i>;
125 return simde_mm_add_epi32(
126 a, simde_mm_min_epu32(simde_mm_xor_si128(a, simde_mm_cmpeq_epi32(a, a)), b));
131simde__m128i
Average(simde__m128i a, simde__m128i b);
136 simde__m128i c = simde_mm_set1_epi8(
static_cast<char>(128));
137 return simde_mm_xor_si128(c,
138 simde_mm_avg_epu8(simde_mm_xor_si128(c, a), simde_mm_xor_si128(c, b)));
144 simde__m128i c = simde_mm_set1_epi16(
static_cast<short>(32768));
145 return simde_mm_xor_si128(c,
146 simde_mm_avg_epu16(simde_mm_xor_si128(c, a), simde_mm_xor_si128(c, b)));
152 simde__m128i sum = simde_mm_add_epi32(simde_mm_srai_epi32(a, 1), simde_mm_srai_epi32(b, 1));
153 return simde_mm_add_epi32(sum,
154 simde_mm_and_si128(simde_mm_or_si128(a, b), simde_mm_set1_epi32(1)));
158template <
typename To,
typename From>
164 simde__m128i xmm1 = simde_mm_add_epi32(src1, simde_mm_set1_epi32(127));
165 simde__m128i xmm0 = simde_mm_slli_epi32(src1, 31 - 8);
166 xmm0 = simde_mm_srli_epi32(xmm0, 31);
167 xmm0 = simde_mm_add_epi32(xmm0, xmm1);
168 xmm0 = simde_mm_srai_epi32(xmm0, 8);
169 xmm0 = simde_mm_add_epi32(xmm0, simde_mm_set1_epi32(0x4F800000));
170 simde__m128 xmm2 = simde_mm_cvtepi32_ps(src1);
171 return simde_mm_blendv_ps(xmm2, simde_mm_castsi128_ps(xmm0), simde_mm_castsi128_ps(src1));
174inline simde__m128i
PermuteBytes(simde__m128i a, simde__m128i b, simde__m128i c) {
175 simde__m128i d = simde_mm_set1_epi8(0xF);
176 simde__m128i e = simde_mm_sub_epi8(d, simde_mm_and_si128(c, d));
177 return simde_mm_blendv_epi8(simde_mm_shuffle_epi8(a, e), simde_mm_shuffle_epi8(b, e),
178 simde_mm_slli_epi32(c, 3));
196 simde__m128i c = simde_mm_set1_epi8(
static_cast<char>(128));
197 return simde_mm_cmpgt_epi8(simde_mm_xor_si128(a, c), simde_mm_xor_si128(b, c));
207 simde__m128i c = simde_mm_set1_epi16(
static_cast<short>(32768));
208 return simde_mm_cmpgt_epi16(simde_mm_xor_si128(a, c), simde_mm_xor_si128(b, c));
212template <
typename To,
typename From>
218 simde__m128 xmm2 = simde_mm_cmpunord_ps(src1, src1);
219 simde__m128i xmm0 = simde_mm_cvttps_epi32(src1);
220 simde__m128i xmm1 = simde_mm_cmpeq_epi32(xmm0, simde_mm_set1_epi32(INT_MIN));
221 xmm1 = simde_mm_andnot_si128(simde_mm_castps_si128(src1), xmm1);
222 simde__m128 dest = simde_mm_blendv_ps(simde_mm_castsi128_ps(xmm0),
223 simde_mm_castsi128_ps(simde_mm_set1_epi32(INT_MAX)),
224 simde_mm_castsi128_ps(xmm1));
225 return simde_mm_andnot_si128(simde_mm_castps_si128(xmm2), simde_mm_castps_si128(dest));
237 simde__m128 nan_mask = simde_mm_cmpunord_ps(src1, src1);
238 simde__m128 neg_mask = simde_mm_cmplt_ps(src1, simde_mm_setzero_ps());
239 simde__m128 max_val = simde_mm_set1_ps(4294967295.0f);
240 simde__m128 overflow_mask = simde_mm_cmpge_ps(src1, max_val);
242 simde__m128 clamped = simde_mm_max_ps(src1, simde_mm_setzero_ps());
243 clamped = simde_mm_min_ps(clamped, max_val);
245 simde__m128 half_range = simde_mm_set1_ps(2147483648.0f);
246 simde__m128 high_bit_mask = simde_mm_cmpge_ps(clamped, half_range);
248 simde__m128 adjusted = simde_mm_sub_ps(clamped, simde_mm_and_ps(high_bit_mask, half_range));
249 simde__m128i low_bits = simde_mm_cvttps_epi32(adjusted);
250 simde__m128i high_bit = simde_mm_and_si128(simde_mm_castps_si128(high_bit_mask),
251 simde_mm_set1_epi32(
static_cast<int>(0x80000000u)));
252 simde__m128i result = simde_mm_or_si128(low_bits, high_bit);
254 result = simde_mm_andnot_si128(simde_mm_castps_si128(nan_mask), result);
255 result = simde_mm_andnot_si128(simde_mm_castps_si128(neg_mask), result);
256 result = simde_mm_or_si128(
257 simde_mm_andnot_si128(simde_mm_castps_si128(overflow_mask), result),
258 simde_mm_and_si128(simde_mm_castps_si128(overflow_mask), simde_mm_set1_epi32(-1)));
269 b = simde_mm_srli_epi64(simde_mm_slli_epi64(b, 61), 61);
270 return simde_mm_castps_si128(simde_mm_insert_ps(
271 simde_mm_castsi128_ps(simde_mm_srl_epi64(a, b)),
272 simde_mm_castsi128_ps(simde_mm_srl_epi64(simde_mm_srli_si128(a, 4), b)), 0x10));
281 int shift = simde_mm_extract_epi8(b, 15) & 0x7;
285 simde__m128i low_shifted = simde_mm_sll_epi64(a, simde_mm_cvtsi32_si128(shift));
286 simde__m128i high_carry = simde_mm_srl_epi64(a, simde_mm_cvtsi32_si128(64 - shift));
287 high_carry = simde_mm_slli_si128(high_carry, 8);
288 return simde_mm_or_si128(low_shifted, high_carry);
297 int shift_bytes = (simde_mm_extract_epi8(b, 0) >> 3) & 0xF;
298 if (shift_bytes == 0)
300 if (shift_bytes >= 16)
301 return simde_mm_setzero_si128();
303 alignas(16) u8 src[16], dst[16];
304 simde_mm_store_si128(
reinterpret_cast<simde__m128i*
>(src), a);
305 memset(dst, 0,
sizeof(dst));
306 memcpy(dst + shift_bytes, src, 16 - shift_bytes);
307 return simde_mm_load_si128(
reinterpret_cast<const simde__m128i*
>(dst));
316 int shift_bytes = (simde_mm_extract_epi8(b, 0) >> 3) & 0xF;
317 if (shift_bytes == 0)
319 if (shift_bytes >= 16)
320 return simde_mm_setzero_si128();
322 alignas(16) u8 src[16], dst[16];
323 simde_mm_store_si128(
reinterpret_cast<simde__m128i*
>(src), a);
324 memset(dst, 0,
sizeof(dst));
325 memcpy(dst, src + shift_bytes, 16 - shift_bytes);
326 return simde_mm_load_si128(
reinterpret_cast<const simde__m128i*
>(dst));
336 simde__m128i zero = simde_mm_setzero_si128();
337 simde__m128i a_lo = simde_mm_unpacklo_epi16(a, zero);
338 simde__m128i a_hi = simde_mm_unpackhi_epi16(a, zero);
339 simde__m128i s_lo = simde_mm_unpacklo_epi16(count, zero);
340 simde__m128i s_hi = simde_mm_unpackhi_epi16(count, zero);
341 simde__m128i r_lo = simde_mm_sllv_epi32(a_lo, s_lo);
342 simde__m128i r_hi = simde_mm_sllv_epi32(a_hi, s_hi);
343 simde__m128i mask16 = simde_mm_set1_epi32(0xFFFF);
344 r_lo = simde_mm_and_si128(r_lo, mask16);
345 r_hi = simde_mm_and_si128(r_hi, mask16);
346 return simde_mm_packus_epi32(r_lo, r_hi);
358 simde__m128i zero = simde_mm_setzero_si128();
359 simde__m128i a_lo = simde_mm_unpacklo_epi16(a, zero);
360 simde__m128i a_hi = simde_mm_unpackhi_epi16(a, zero);
361 simde__m128i s_lo = simde_mm_unpacklo_epi16(count, zero);
362 simde__m128i s_hi = simde_mm_unpackhi_epi16(count, zero);
363 simde__m128i r_lo = simde_mm_srlv_epi32(a_lo, s_lo);
364 simde__m128i r_hi = simde_mm_srlv_epi32(a_hi, s_hi);
365 return simde_mm_packus_epi32(r_lo, r_hi);
371 simde__m128i zero = simde_mm_setzero_si128();
372 simde__m128i a_lo = simde_mm_srai_epi32(simde_mm_unpacklo_epi16(a, a), 16);
373 simde__m128i a_hi = simde_mm_srai_epi32(simde_mm_unpackhi_epi16(a, a), 16);
374 simde__m128i s_lo = simde_mm_unpacklo_epi16(count, zero);
375 simde__m128i s_hi = simde_mm_unpackhi_epi16(count, zero);
376 simde__m128i r_lo = simde_mm_srav_epi32(a_lo, s_lo);
377 simde__m128i r_hi = simde_mm_srav_epi32(a_hi, s_hi);
378 return simde_mm_packs_epi32(r_lo, r_hi);
384 simde__m128i zero = simde_mm_setzero_si128();
385 simde__m128i a_lo = simde_mm_unpacklo_epi8(a, zero);
386 simde__m128i a_hi = simde_mm_unpackhi_epi8(a, zero);
387 simde__m128i s_lo = simde_mm_unpacklo_epi8(count, zero);
388 simde__m128i s_hi = simde_mm_unpackhi_epi8(count, zero);
391 simde__m128i mask8 = simde_mm_set1_epi16(0xFF);
392 r_lo = simde_mm_and_si128(r_lo, mask8);
393 r_hi = simde_mm_and_si128(r_hi, mask8);
394 return simde_mm_packus_epi16(r_lo, r_hi);
399 return simde_mm_shuffle_epi8(
400 v, simde_mm_load_si128(
reinterpret_cast<const simde__m128i*
>(
kVectorMaskL)));
411 simde_mm_storeu_si128(
reinterpret_cast<simde__m128i*
>(host),
412 simde_mm_loadu_si128(
reinterpret_cast<const simde__m128i*
>(bytes)));
413 }
else if (count >= 8) {
414 std::memcpy(host, bytes, 8);
415 std::memcpy(host + count - 8, bytes + count - 8, 8);
416 }
else if (count >= 4) {
417 std::memcpy(host, bytes, 4);
418 std::memcpy(host + count - 4, bytes + count - 4, 4);
419 }
else if (count >= 2) {
420 std::memcpy(host, bytes, 2);
421 std::memcpy(host + count - 2, bytes + count - 2, 2);
422 }
else if (count == 1) {
433 alignas(16) u8 bytes[16];
434 simde_mm_store_si128(
reinterpret_cast<simde__m128i*
>(bytes),
ToGuestByteOrder(v));
445 alignas(16) u8 bytes[16];
446 simde_mm_store_si128(
reinterpret_cast<simde__m128i*
>(bytes),
ToGuestByteOrder(v));
447 const u32 count = ea & 0xF;
461 if (right_ea == left_ea + 16 && right_host == left_host + (16 - (left_ea & 0xF))) {
462 simde_mm_storeu_si128(
reinterpret_cast<simde__m128i*
>(left_host),
ToGuestByteOrder(v));
489template <
bool Signed>
491 const auto above = simde_mm_cmpge_ps(scaled, simde_mm_set1_ps(Signed ? 0x1p31f : 0x1p32f));
492 const auto below = Signed ? simde_mm_cmplt_ps(scaled, simde_mm_set1_ps(-0x1p31f))
493 : simde_mm_cmple_ps(scaled, simde_mm_set1_ps(-1.0f));
494 return simde_mm_movemask_ps(simde_mm_or_ps(above, below)) != 0;
506inline bool AnyLaneDiffers(simde__m128i wrapped, simde__m128i saturated) {
507 return simde_mm_movemask_epi8(simde_mm_cmpeq_epi8(wrapped, saturated)) != 0xFFFF;
519template <u32 Bits,
bool Signed>
521 if constexpr (Bits == 8) {
522 return detail::AnyLaneDiffers(simde_mm_add_epi8(a, b),
523 Signed ? simde_mm_adds_epi8(a, b) : simde_mm_adds_epu8(a, b));
524 }
else if constexpr (Bits == 16) {
525 return detail::AnyLaneDiffers(simde_mm_add_epi16(a, b),
526 Signed ? simde_mm_adds_epi16(a, b) : simde_mm_adds_epu16(a, b));
527 }
else if constexpr (Signed) {
528 const auto sum = simde_mm_add_epi32(a, b);
529 const auto overflow =
530 simde_mm_and_si128(simde_mm_xor_si128(a, sum), simde_mm_xor_si128(b, sum));
531 return simde_mm_movemask_ps(simde_mm_castsi128_ps(overflow)) != 0;
533 const auto sum = simde_mm_add_epi32(a, b);
534 return simde_mm_movemask_epi8(simde_mm_cmpeq_epi32(simde_mm_max_epu32(a, sum), sum)) != 0xFFFF;
547template <u32 Bits,
bool Signed>
549 if constexpr (Bits == 8) {
550 return detail::AnyLaneDiffers(simde_mm_sub_epi8(a, b),
551 Signed ? simde_mm_subs_epi8(a, b) : simde_mm_subs_epu8(a, b));
552 }
else if constexpr (Bits == 16) {
553 return detail::AnyLaneDiffers(simde_mm_sub_epi16(a, b),
554 Signed ? simde_mm_subs_epi16(a, b) : simde_mm_subs_epu16(a, b));
555 }
else if constexpr (Signed) {
556 const auto difference = simde_mm_sub_epi32(a, b);
557 const auto overflow =
558 simde_mm_and_si128(simde_mm_xor_si128(a, b), simde_mm_xor_si128(a, difference));
559 return simde_mm_movemask_ps(simde_mm_castsi128_ps(overflow)) != 0;
561 return simde_mm_movemask_epi8(simde_mm_cmpeq_epi32(simde_mm_max_epu32(a, b), a)) != 0xFFFF;
572template <u32 SourceBits,
bool SignedDest>
574 constexpr u32 kDestBits = SourceBits / 2;
575 constexpr u32 kRange = (1u << kDestBits) - 1;
576 constexpr u32 kLow = SignedDest ? (0u - (1u << (kDestBits - 1))) : 0u;
577 if constexpr (SourceBits == 16) {
578 const auto low = simde_mm_set1_epi16(
static_cast<i16
>(kLow));
579 const auto range = simde_mm_set1_epi16(
static_cast<i16
>(kRange));
580 const auto outside = simde_mm_or_si128(simde_mm_subs_epu16(simde_mm_sub_epi16(a, low), range),
581 simde_mm_subs_epu16(simde_mm_sub_epi16(b, low), range));
582 return simde_mm_movemask_epi8(simde_mm_cmpeq_epi8(outside, simde_mm_setzero_si128())) != 0xFFFF;
584 const auto low = simde_mm_set1_epi32(
static_cast<i32
>(kLow));
585 const auto range = simde_mm_set1_epi32(
static_cast<i32
>(kRange));
586 const auto first = simde_mm_sub_epi32(a, low);
587 const auto second = simde_mm_sub_epi32(b, low);
589 simde_mm_and_si128(simde_mm_cmpeq_epi32(simde_mm_max_epu32(first, range), range),
590 simde_mm_cmpeq_epi32(simde_mm_max_epu32(second, range), range));
591 return simde_mm_movemask_epi8(inside) != 0xFFFF;
604inline constexpr PackRange kUnchecked{
false, 0.0, 0.0};
605inline constexpr PackRange kByteRange{
true, 0.0, 255.0};
606inline constexpr PackRange kShortRange{
true, -32767.0, 32767.0};
607inline constexpr PackRange kSigned10Range{
true, -511.0, 511.0};
608inline constexpr PackRange kSigned20Range{
true, -524287.0, 524287.0};
609inline constexpr PackRange kTwoBitRange{
true, 0.0, 3.0};
610inline constexpr PackRange kFourBitRange{
true, 0.0, 15.0};
613inline constexpr std::array<std::array<PackRange, 4>, 7> kPackD3DRanges = {{
614 {kByteRange, kByteRange, kByteRange, kByteRange},
615 {kShortRange, kShortRange, kUnchecked, kUnchecked},
616 {kSigned10Range, kSigned10Range, kSigned10Range, kTwoBitRange},
617 {kUnchecked, kUnchecked, kUnchecked, kUnchecked},
618 {kShortRange, kShortRange, kShortRange, kShortRange},
619 {kUnchecked, kUnchecked, kUnchecked, kUnchecked},
620 {kSigned20Range, kSigned20Range, kSigned20Range, kFourBitRange},
624template <u32 Type,
bool High>
625inline constexpr std::array<f32, 4> kPackD3DBounds = [] {
626 std::array<f32, 4> bounds{};
627 for (u32 lane = 0; lane < 4; ++lane) {
628 const PackRange& range = kPackD3DRanges[Type][3 - lane];
630 range.checked ?
static_cast<f32
>(3.0 + (High ? range.high : range.low) / 4194304.0) : 0.0f;
637inline constexpr std::array<u32, 4> kPackD3DChecked = [] {
638 std::array<u32, 4> mask{};
639 for (u32 lane = 0; lane < 4; ++lane) {
640 mask[lane] = kPackD3DRanges[Type][3 - lane].checked ? 0xFFFFFFFFu : 0u;
656 const auto low = simde_mm_loadu_ps(detail::kPackD3DBounds<Type, false>.data());
657 const auto high = simde_mm_loadu_ps(detail::kPackD3DBounds<Type, true>.data());
659 simde_mm_loadu_ps(
reinterpret_cast<const f32*
>(detail::kPackD3DChecked<Type>.data()));
661 simde_mm_and_ps(simde_mm_cmpge_ps(source, low), simde_mm_cmple_ps(source, high));
662 const auto outside = simde_mm_andnot_ps(inside, simde_mm_cmpord_ps(source, source));
663 return simde_mm_movemask_ps(simde_mm_and_ps(outside, checked)) != 0;
681 std::array<PackField, 4> lanes;
686inline constexpr std::array<PackLayout, 7> kPackLayouts = {{
687 {{{{16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 8, 0}}}, 4,
false},
688 {{{{16, 16, 0x8000}, {0, 16, 0x8000}, {}, {}}}, 2,
false},
689 {{{{0, 10, 0x200}, {10, 10, 0x200}, {20, 10, 0x200}, {30, 2, 0}}}, 4,
false},
690 {{{{16, 16, 0}, {0, 16, 0}, {}, {}}}, 2,
true},
691 {{{{48, 16, 0x8000}, {32, 16, 0x8000}, {16, 16, 0x8000}, {0, 16, 0x8000}}}, 4,
false},
692 {{{{48, 16, 0}, {32, 16, 0}, {16, 16, 0}, {0, 16, 0}}}, 4,
true},
693 {{{{0, 20, 0x80000}, {20, 20, 0x80000}, {40, 20, 0x80000}, {60, 4, 0}}}, 4,
false},
704inline u64 PackInteger(u32 bits,
const PackRange& range,
const PackField& lane, u8& saturated) {
705 const u64 mask = (u64{1} << lane.width) - 1;
706 if ((bits & 0x7FFFFFFFu) > 0x7F800000u) {
707 return lane.nan_field;
709 i64 k = (bits >> 31) != 0 ? -0x100000000LL : static_cast<i64>(bits) - 0x40400000LL;
711 const i64 low = static_cast<i64>(range.low);
712 const i64 high = static_cast<i64>(range.high);
713 if (k < low || k > high) {
715 k = k < low ? low : high;
718 return static_cast<u64
>(k) & mask;
728inline u64 PackHalf(u32 bits) {
729 const u32 sign = (bits >> 16) & 0x8000u;
730 const u32 magnitude = bits & 0x7FFFFFFFu;
731 if (magnitude > 0x477FE000u) {
732 return sign | 0x7FFFu;
734 const u32 exponent = magnitude >> 23;
735 if (exponent <= 0x70u) {
738 return sign | (((exponent - 0x70u) << 10) + ((magnitude & 0x7FE000u) >> 13));
749inline u64 PackElements(
const VRegister& source, u8& saturated) {
750 if constexpr (Type == 0) {
751 const auto bits = simde_mm_load_si128(
reinterpret_cast<const simde__m128i*
>(source.u32));
752 const auto offset = simde_mm_sub_epi32(bits, simde_mm_set1_epi32(0x40400000));
753 const auto negative = simde_mm_srai_epi32(bits, 31);
755 simde_mm_or_si128(negative, simde_mm_cmpgt_epi32(simde_mm_setzero_si128(), offset));
757 simde_mm_andnot_si128(below, simde_mm_cmpgt_epi32(offset, simde_mm_set1_epi32(255)));
758 const auto not_a_number = simde_mm_cmpgt_epi32(
759 simde_mm_and_si128(bits, simde_mm_set1_epi32(0x7FFFFFFF)), simde_mm_set1_epi32(0x7F800000));
760 const auto outside = simde_mm_andnot_si128(not_a_number, simde_mm_or_si128(below, above));
761 saturated = simde_mm_movemask_epi8(outside) != 0 ? 1 : 0;
763 simde_mm_andnot_si128(simde_mm_or_si128(below, not_a_number),
764 simde_mm_or_si128(simde_mm_and_si128(above, simde_mm_set1_epi32(255)),
765 simde_mm_andnot_si128(above, offset)));
766 const auto bytes = simde_mm_shuffle_epi8(
767 clamped, simde_mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 12, 8, 4));
768 return static_cast<u32
>(simde_mm_cvtsi128_si32(bytes));
770 constexpr const detail::PackLayout& kLayout = detail::kPackLayouts[Type];
772 for (u32 i = 0; i < kLayout.count; ++i) {
773 const u32 bits = source.u32[3 - i];
774 const detail::PackField& lane = kLayout.lanes[i];
775 const u64 field = kLayout.half ? detail::PackHalf(bits)
776 : detail::PackInteger(bits, detail::kPackD3DRanges[Type][i],
778 packed |= field << lane.shift;
795template <u32 Type, u32 Mask, u32 Shift>
798 const u64 packed = detail::PackElements<Type>(source, saturated);
799 const u32 lo =
static_cast<u32
>(packed);
800 const u32 hi =
static_cast<u32
>(packed >> 32);
801 if constexpr (Mask == 3 && Shift == 3) {
804 dest.u32[Shift] = lo;
805 if constexpr (Mask >= 2 && Shift < 3) {
806 dest.u32[Shift + 1] = hi;
void StoreVectorRight(u8 *host, u32 ea, simde__m128i v)
Definition vmx.h:444
simde__m128i AddSaturate(simde__m128i a, simde__m128i b)
u8 PackD3D(VRegister &dest, const VRegister &source)
Definition vmx.h:796
bool IsPackD3DSaturating(simde__m128 source) noexcept
Definition vmx.h:655
simde__m128i PermuteBytes(simde__m128i a, simde__m128i b, simde__m128i c)
Definition vmx.h:174
simde__m128i Average(simde__m128i a, simde__m128i b)
constexpr u8 kVectorMaskL[]
Definition vmx.h:39
simde__m128i ToGuestByteOrder(simde__m128i v)
Definition vmx.h:398
simde__m128i CompareGreater(simde__m128i a, simde__m128i b)
constexpr u8 kVectorShiftTableL[]
Definition vmx.h:77
simde__m128i ShiftLeftBits(simde__m128i a, simde__m128i b)
Definition vmx.h:280
simde__m128i ShiftLeftBytes(simde__m128i a, simde__m128i b)
Definition vmx.h:296
simde__m128i ShiftLeftLanes(simde__m128i a, simde__m128i count)
bool IsSubSaturating(simde__m128i a, simde__m128i b) noexcept
Definition vmx.h:548
void StoreVectorPair(u8 *left_host, u32 left_ea, u8 *right_host, u32 right_ea, simde__m128i v)
Definition vmx.h:459
VectorOf< To > Convert(VectorOf< From > src)
simde__m128i ShiftRightLanes(simde__m128i a, simde__m128i count)
constexpr u8 kVectorShiftTableR[]
Definition vmx.h:96
constexpr u8 kVectorMaskR[]
Definition vmx.h:58
bool IsAddSaturating(simde__m128i a, simde__m128i b) noexcept
Definition vmx.h:520
void StoreVectorBytes(u8 *host, const u8 *bytes, u32 count)
Definition vmx.h:409
bool IsPackSaturating(simde__m128i a, simde__m128i b) noexcept
Definition vmx.h:573
void StoreVectorLeft(u8 *host, u32 ea, simde__m128i v)
Definition vmx.h:432
VectorOf< To > ConvertSaturate(VectorOf< From > src)
simde__m128i ShiftRightBits(simde__m128i a, simde__m128i b)
Definition vmx.h:268
bool IsConvertSaturating(simde__m128 scaled) noexcept
Definition vmx.h:490
std::conditional_t< std::is_floating_point_v< T >, simde__m128, simde__m128i > VectorOf
Definition vmx.h:116
simde__m128i ShiftRightBytes(simde__m128i a, simde__m128i b)
Definition vmx.h:315
Integer types, byte order wrappers and size literals.