| #if !can_use_sse41 || !x86_64 |
| |
| uint64_t Hash64(const char *s, size_t len) { |
| FARMHASH_DIE_IF_MISCONFIGURED; |
| return s == NULL ? 0 : len; |
| } |
| |
| uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { |
| FARMHASH_DIE_IF_MISCONFIGURED; |
| return seed + Hash64(s, len); |
| } |
| |
| uint64_t Hash64WithSeeds(const char *s, size_t len, |
| uint64_t seed0, uint64_t seed1) { |
| FARMHASH_DIE_IF_MISCONFIGURED; |
| return seed0 + seed1 + Hash64(s, len); |
| } |
| |
| #else |
| |
| #undef Fetch |
| #define Fetch Fetch64 |
| |
| #undef Rotate |
| #define Rotate Rotate64 |
| |
| #undef Bswap |
| #define Bswap Bswap64 |
| |
| // Helpers for data-parallel operations (1x 128 bits or 2x 64 or 4x 32). |
| STATIC_INLINE __m128i Add(__m128i x, __m128i y) { return _mm_add_epi64(x, y); } |
| STATIC_INLINE __m128i Xor(__m128i x, __m128i y) { return _mm_xor_si128(x, y); } |
| STATIC_INLINE __m128i Mul(__m128i x, __m128i y) { return _mm_mullo_epi32(x, y); } |
| STATIC_INLINE __m128i Shuf(__m128i x, __m128i y) { return _mm_shuffle_epi8(y, x); } |
| |
| // Requires n >= 256. Requires SSE4.1. Should be slightly faster if the |
| // compiler uses AVX instructions (e.g., use the -mavx flag with GCC). |
| STATIC_INLINE uint64_t Hash64Long(const char* s, size_t n, |
| uint64_t seed0, uint64_t seed1) { |
| const __m128i kShuf = |
| _mm_set_epi8(4, 11, 10, 5, 8, 15, 6, 9, 12, 2, 14, 13, 0, 7, 3, 1); |
| const __m128i kMult = |
| _mm_set_epi8(0xbd, 0xd6, 0x33, 0x39, 0x45, 0x54, 0xfa, 0x03, |
| 0x34, 0x3e, 0x33, 0xed, 0xcc, 0x9e, 0x2d, 0x51); |
| uint64_t seed2 = (seed0 + 113) * (seed1 + 9); |
| uint64_t seed3 = (Rotate(seed0, 23) + 27) * (Rotate(seed1, 30) + 111); |
| __m128i d0 = _mm_cvtsi64_si128(seed0); |
| __m128i d1 = _mm_cvtsi64_si128(seed1); |
| __m128i d2 = Shuf(kShuf, d0); |
| __m128i d3 = Shuf(kShuf, d1); |
| __m128i d4 = Xor(d0, d1); |
| __m128i d5 = Xor(d1, d2); |
| __m128i d6 = Xor(d2, d4); |
| __m128i d7 = _mm_set1_epi32(seed2 >> 32); |
| __m128i d8 = Mul(kMult, d2); |
| __m128i d9 = _mm_set1_epi32(seed3 >> 32); |
| __m128i d10 = _mm_set1_epi32(seed3); |
| __m128i d11 = Add(d2, _mm_set1_epi32(seed2)); |
| const char* end = s + (n & ~static_cast<size_t>(255)); |
| do { |
| __m128i z; |
| z = Fetch128(s); |
| d0 = Add(d0, z); |
| d1 = Shuf(kShuf, d1); |
| d2 = Xor(d2, d0); |
| d4 = Xor(d4, z); |
| d4 = Xor(d4, d1); |
| std::swap(d0, d6); |
| z = Fetch128(s + 16); |
| d5 = Add(d5, z); |
| d6 = Shuf(kShuf, d6); |
| d8 = Shuf(kShuf, d8); |
| d7 = Xor(d7, d5); |
| d0 = Xor(d0, z); |
| d0 = Xor(d0, d6); |
| std::swap(d5, d11); |
| z = Fetch128(s + 32); |
| d1 = Add(d1, z); |
| d2 = Shuf(kShuf, d2); |
| d4 = Shuf(kShuf, d4); |
| d5 = Xor(d5, z); |
| d5 = Xor(d5, d2); |
| std::swap(d10, d4); |
| z = Fetch128(s + 48); |
| d6 = Add(d6, z); |
| d7 = Shuf(kShuf, d7); |
| d0 = Shuf(kShuf, d0); |
| d8 = Xor(d8, d6); |
| d1 = Xor(d1, z); |
| d1 = Add(d1, d7); |
| z = Fetch128(s + 64); |
| d2 = Add(d2, z); |
| d5 = Shuf(kShuf, d5); |
| d4 = Add(d4, d2); |
| d6 = Xor(d6, z); |
| d6 = Xor(d6, d11); |
| std::swap(d8, d2); |
| z = Fetch128(s + 80); |
| d7 = Xor(d7, z); |
| d8 = Shuf(kShuf, d8); |
| d1 = Shuf(kShuf, d1); |
| d0 = Add(d0, d7); |
| d2 = Add(d2, z); |
| d2 = Add(d2, d8); |
| std::swap(d1, d7); |
| z = Fetch128(s + 96); |
| d4 = Shuf(kShuf, d4); |
| d6 = Shuf(kShuf, d6); |
| d8 = Mul(kMult, d8); |
| d5 = Xor(d5, d11); |
| d7 = Xor(d7, z); |
| d7 = Add(d7, d4); |
| std::swap(d6, d0); |
| z = Fetch128(s + 112); |
| d8 = Add(d8, z); |
| d0 = Shuf(kShuf, d0); |
| d2 = Shuf(kShuf, d2); |
| d1 = Xor(d1, d8); |
| d10 = Xor(d10, z); |
| d10 = Xor(d10, d0); |
| std::swap(d11, d5); |
| z = Fetch128(s + 128); |
| d4 = Add(d4, z); |
| d5 = Shuf(kShuf, d5); |
| d7 = Shuf(kShuf, d7); |
| d6 = Add(d6, d4); |
| d8 = Xor(d8, z); |
| d8 = Xor(d8, d5); |
| std::swap(d4, d10); |
| z = Fetch128(s + 144); |
| d0 = Add(d0, z); |
| d1 = Shuf(kShuf, d1); |
| d2 = Add(d2, d0); |
| d4 = Xor(d4, z); |
| d4 = Xor(d4, d1); |
| z = Fetch128(s + 160); |
| d5 = Add(d5, z); |
| d6 = Shuf(kShuf, d6); |
| d8 = Shuf(kShuf, d8); |
| d7 = Xor(d7, d5); |
| d0 = Xor(d0, z); |
| d0 = Xor(d0, d6); |
| std::swap(d2, d8); |
| z = Fetch128(s + 176); |
| d1 = Add(d1, z); |
| d2 = Shuf(kShuf, d2); |
| d4 = Shuf(kShuf, d4); |
| d5 = Mul(kMult, d5); |
| d5 = Xor(d5, z); |
| d5 = Xor(d5, d2); |
| std::swap(d7, d1); |
| z = Fetch128(s + 192); |
| d6 = Add(d6, z); |
| d7 = Shuf(kShuf, d7); |
| d0 = Shuf(kShuf, d0); |
| d8 = Add(d8, d6); |
| d1 = Xor(d1, z); |
| d1 = Xor(d1, d7); |
| std::swap(d0, d6); |
| z = Fetch128(s + 208); |
| d2 = Add(d2, z); |
| d5 = Shuf(kShuf, d5); |
| d4 = Xor(d4, d2); |
| d6 = Xor(d6, z); |
| d6 = Xor(d6, d9); |
| std::swap(d5, d11); |
| z = Fetch128(s + 224); |
| d7 = Add(d7, z); |
| d8 = Shuf(kShuf, d8); |
| d1 = Shuf(kShuf, d1); |
| d0 = Xor(d0, d7); |
| d2 = Xor(d2, z); |
| d2 = Xor(d2, d8); |
| std::swap(d10, d4); |
| z = Fetch128(s + 240); |
| d3 = Add(d3, z); |
| d4 = Shuf(kShuf, d4); |
| d6 = Shuf(kShuf, d6); |
| d7 = Mul(kMult, d7); |
| d5 = Add(d5, d3); |
| d7 = Xor(d7, z); |
| d7 = Xor(d7, d4); |
| std::swap(d3, d9); |
| s += 256; |
| } while (s != end); |
| d6 = Add(Mul(kMult, d6), _mm_cvtsi64_si128(n)); |
| if (n % 256 != 0) { |
| d7 = Add(_mm_shuffle_epi32(d8, (0 << 6) + (3 << 4) + (2 << 2) + (1 << 0)), d7); |
| d8 = Add(Mul(kMult, d8), _mm_cvtsi64_si128(farmhashxo::Hash64(s, n % 256))); |
| } |
| __m128i t[8]; |
| d0 = Mul(kMult, Shuf(kShuf, Mul(kMult, d0))); |
| d3 = Mul(kMult, Shuf(kShuf, Mul(kMult, d3))); |
| d9 = Mul(kMult, Shuf(kShuf, Mul(kMult, d9))); |
| d1 = Mul(kMult, Shuf(kShuf, Mul(kMult, d1))); |
| d0 = Add(d11, d0); |
| d3 = Xor(d7, d3); |
| d9 = Add(d8, d9); |
| d1 = Add(d10, d1); |
| d4 = Add(d3, d4); |
| d5 = Add(d9, d5); |
| d6 = Xor(d1, d6); |
| d2 = Add(d0, d2); |
| t[0] = d0; |
| t[1] = d3; |
| t[2] = d9; |
| t[3] = d1; |
| t[4] = d4; |
| t[5] = d5; |
| t[6] = d6; |
| t[7] = d2; |
| return farmhashxo::Hash64(reinterpret_cast<const char*>(t), sizeof(t)); |
| } |
| |
| uint64_t Hash64(const char *s, size_t len) { |
| // Empirically, farmhashxo seems faster until length 512. |
| return len >= 512 ? Hash64Long(s, len, k2, k1) : farmhashxo::Hash64(s, len); |
| } |
| |
| uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { |
| return len >= 512 ? Hash64Long(s, len, k1, seed) : |
| farmhashxo::Hash64WithSeed(s, len, seed); |
| } |
| |
| uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1) { |
| return len >= 512 ? Hash64Long(s, len, seed0, seed1) : |
| farmhashxo::Hash64WithSeeds(s, len, seed0, seed1); |
| } |
| |
| #endif |