18#include "prism/internal/xxh3.h"
26#if defined(PRISM_HAS_NEON) && defined(PRISM_LITTLE_ENDIAN_COMPTIME)
29#elif defined(PRISM_HAS_SSE2)
30 #include <emmintrin.h>
34#if defined(__SIZEOF_INT128__)
36XXH3_mul128_fold64(uint64_t lhs, uint64_t rhs) {
37 __uint128_t x = (__uint128_t) lhs * (__uint128_t) rhs;
38 return ((uint64_t) (x & 0xFFFFFFFFFFFFFFFFULL)) ^ ((uint64_t) (x >> 64));
41#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))
46XXH3_mul128_fold64(uint64_t lhs, uint64_t rhs) {
48#if defined(_MSC_VER) && defined(_M_X64)
49 lo = _umul128(lhs, rhs, &hi);
50#elif defined(_MSC_VER) && defined(_M_ARM64)
51 hi = __umulh(lhs, rhs);
54 uint64_t lo_lo = (lhs & 0xFFFFFFFF) * (rhs & 0xFFFFFFFF);
55 uint64_t hi_lo = (lhs >> 32) * (rhs & 0xFFFFFFFF);
56 uint64_t lo_hi = (lhs & 0xFFFFFFFF) * (rhs >> 32);
57 uint64_t hi_hi = (lhs >> 32) * (rhs >> 32);
59 uint64_t cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi;
60 hi = hi_hi + (hi_lo >> 32) + (cross >> 32);
61 lo = (cross << 32) | (lo_lo & 0xFFFFFFFF);
68read32(
const void* ptr) {
70 memcpy(&val, ptr,
sizeof(val));
71 if (!PRISM_LITTLE_ENDIAN_RUNTIME) {
78read64(
const void* ptr) {
80 memcpy(&val, ptr,
sizeof(val));
81 if (!PRISM_LITTLE_ENDIAN_RUNTIME) {
82 val = pm_bswap64(val);
87static const uint64_t PRIME32_1 = 0x9E3779B1U;
88static const uint64_t PRIME32_2 = 0x85EBCA77U;
89static const uint64_t PRIME32_3 = 0xC2B2AE3DU;
90static const uint64_t PRIME64_1 = 0x9E3779B185EBCA87ULL;
91static const uint64_t PRIME64_2 = 0xC2B2AE3D27D4EB4FULL;
92static const uint64_t PRIME64_3 = 0x165667B19E3779F9ULL;
93static const uint64_t PRIME64_4 = 0x85EBCA77C2B2AE63ULL;
94static const uint64_t PRIME64_5 = 0x27D4EB2F165667C5ULL;
95static const uint64_t PRIME_MX1 = 0x165667919E3779F9ULL;
96static const uint64_t PRIME_MX2 = 0x9FB21C651E98DF25ULL;
98static const uint8_t secret[192] = {
99 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,
100 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,
101 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21,
102 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c,
103 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3,
104 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8,
105 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d,
106 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64,
107 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb,
108 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e,
109 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce,
110 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,
114avalanche(uint64_t x) {
122avalanche_XXH64(uint64_t x) {
133 return avalanche_XXH64(read64(secret + 56) ^ read64(secret + 64));
137XXH3_64_1to3(
const uint8_t *input,
size_t length) {
138 uint32_t combined = (uint32_t) input[length - 1] | ((uint32_t) length << 8) | ((uint32_t) input[0] << 16) | ((uint32_t) input[length >> 1] << 24);
139 return avalanche_XXH64((uint64_t) (read32(secret) ^ read32(secret + 4)) ^ (uint64_t) combined);
143XXH3_64_4to8(
const uint8_t *input,
size_t length) {
144#define rot(x_, r_) (((x_) << (r_)) | ((x_) >> (64 - (r_))))
146 uint64_t combined = (uint64_t) read32(input + length - 4) | ((uint64_t) read32(input) << 32);
147 uint64_t value = (read64(secret + 8) ^ read64(secret + 16)) ^ combined;
148 value ^= rot(value, 49) ^ rot(value, 24);
150 value ^= ((value >> 35) + length);
152 value ^= (value >> 28);
159XXH3_64_9to16(
const uint8_t *input,
size_t length) {
160 uint64_t lo = (read64(secret + 24) ^ read64(secret + 32)) ^ read64(input);
161 uint64_t hi = (read64(secret + 40) ^ read64(secret + 48)) ^ read64(input + length - 8);
162 return avalanche(length + pm_bswap64(lo) + hi + XXH3_mul128_fold64(lo, hi));
166XXH3_64_17to240(
const uint8_t *input,
size_t length) {
167#define mix(data_, offset_) XXH3_mul128_fold64(read64((data_)) ^ read64(secret + (offset_)), read64((data_) + 8) ^ read64(secret + (offset_) + 8))
169 uint64_t acc = length * PRIME64_1;
172 size_t idx = (length - 1) / 32;
174 acc += mix(input + idx * 16, idx * 32) + mix(input + length - idx * 16 - 16, idx * 32 + 16);
177 for (
size_t idx = 0; idx < 8; idx++) {
178 acc += mix(input + idx * 16, idx * 16);
180 acc = avalanche(acc);
181 for (
size_t idx = 8; idx < length >> 4; idx++) {
182 acc += mix(input + idx * 16, (idx - 8) * 16 + 3);
184 acc += mix(input + length - 16, 119);
187 return avalanche(acc);
193accumulate(uint64_t acc[8],
const uint8_t *stripe,
size_t secret_offset) {
194#if defined(XXH3_NEON)
195 for (
int idx = 0; idx < 8; idx += 2) {
196 uint64x2_t data = vreinterpretq_u64_u8(vld1q_u8(stripe + 8 * idx));
197 uint64x2_t value = veorq_u64(data, vreinterpretq_u64_u8(vld1q_u8(secret + secret_offset + 8 * idx)));
198 uint64x2_t product = vmull_u32(vmovn_u64(value), vshrn_n_u64(value, 32));
199 vst1q_u64(acc + idx, vaddq_u64(vld1q_u64(acc + idx), vaddq_u64(vextq_u64(data, data, 1), product)));
201#elif defined(XXH3_SSE2)
202 for (
int idx = 0; idx < 8; idx += 2) {
203 __m128i data = _mm_loadu_si128((
const __m128i *) (stripe + 8 * idx));
204 __m128i value = _mm_xor_si128(data, _mm_loadu_si128((
const __m128i *) (secret + secret_offset + 8 * idx)));
205 __m128i product = _mm_mul_epu32(value, _mm_shuffle_epi32(value, _MM_SHUFFLE(0, 3, 0, 1)));
206 _mm_storeu_si128((__m128i *) (acc + idx), _mm_add_epi64(_mm_loadu_si128((
const __m128i *) (acc + idx)), _mm_add_epi64(_mm_shuffle_epi32(data, _MM_SHUFFLE(1, 0, 3, 2)), product)));
209 for (
int idx = 0; idx < 8; idx++) {
210 uint64_t data = read64(stripe + 8 * idx);
211 uint64_t value = data ^ read64(secret + secret_offset + 8 * idx);
212 acc[idx ^ 1] = acc[idx ^ 1] + data;
213 acc[idx] += (value & 0xFFFFFFFF) * (value >> 32);
219XXH3_64_large(
const uint8_t *input,
size_t length) {
220 const size_t secret_length =
sizeof(secret);
221 const size_t stripes_per_block = (secret_length - 64) / 8;
222 const size_t block_size = 64 * stripes_per_block;
223 const size_t block_count = (length - 1) / block_size;
224 const size_t last_offset = block_count * block_size;
227 PRIME32_3, PRIME64_1, PRIME64_2, PRIME64_3,
228 PRIME64_4, PRIME32_2, PRIME64_5, PRIME32_1
231 for (
size_t block_idx = 0; block_idx < block_count; block_idx++) {
232 const uint8_t *block = input + block_idx * block_size;
234 for (
size_t stripe_idx = 0; stripe_idx < stripes_per_block; stripe_idx++) {
235 accumulate(acc, block + stripe_idx * 64, stripe_idx * 8);
238#if defined(XXH3_NEON)
239 const uint32x2_t prime = vdup_n_u32((uint32_t) PRIME32_1);
240 for (
size_t idx = 0; idx < 8; idx += 2) {
241 uint64x2_t value = vld1q_u64(acc + idx);
242 value = veorq_u64(value, vshrq_n_u64(value, 47));
243 value = veorq_u64(value, vreinterpretq_u64_u8(vld1q_u8(secret + secret_length - 64 + idx * 8)));
244 vst1q_u64(acc + idx, vaddq_u64(vmull_u32(vmovn_u64(value), prime), vshlq_n_u64(vmull_u32(vshrn_n_u64(value, 32), prime), 32)));
246#elif defined(XXH3_SSE2)
247 const __m128i prime = _mm_set1_epi32((
int) (uint32_t) PRIME32_1);
248 for (
size_t idx = 0; idx < 8; idx += 2) {
249 __m128i value = _mm_loadu_si128((
const __m128i *) (acc + idx));
250 value = _mm_xor_si128(value, _mm_srli_epi64(value, 47));
251 value = _mm_xor_si128(value, _mm_loadu_si128((
const __m128i *) (secret + secret_length - 64 + idx * 8)));
252 _mm_storeu_si128((__m128i *) (acc + idx), _mm_add_epi64(_mm_mul_epu32(value, prime), _mm_slli_epi64(_mm_mul_epu32(_mm_shuffle_epi32(value, _MM_SHUFFLE(0, 3, 0, 1)), prime), 32)));
255 for (
size_t idx = 0; idx < 8; idx++) {
256 acc[idx] ^= (acc[idx] >> 47);
257 acc[idx] ^= read64(secret + secret_length - 64 + idx * 8);
258 acc[idx] *= PRIME32_1;
263 for (
size_t stripe_idx = 0; stripe_idx < (length - last_offset - 1) / 64; stripe_idx++) {
264 accumulate(acc, input + last_offset + stripe_idx * 64, stripe_idx * 8);
267 accumulate(acc, input + length - 64, secret_length - 71);
269 uint64_t result = (uint64_t) length * PRIME64_1;
270 for (
size_t idx = 0; idx < 4; idx++) {
271 result += XXH3_mul128_fold64(acc[idx * 2] ^ read64(secret + 11 + 16 * idx), acc[idx * 2 + 1] ^ read64(secret + 11 + 16 * idx + 8));
274 return avalanche(result);
278pm_xxh3(
const uint8_t *input,
size_t length) {
280 return XXH3_64_empty();
281 }
else if (length <= 3) {
282 return XXH3_64_1to3(input, length);
283 }
else if (length <= 8) {
284 return XXH3_64_4to8(input, length);
285 }
else if (length <= 16) {
286 return XXH3_64_9to16(input, length);
287 }
else if (length <= 240) {
288 return XXH3_64_17to240(input, length);
290 return XXH3_64_large(input, length);
#define pm_bswap32(x_)
Byte swap utilities for 32-bit and 64-bit integers.