Last active
June 16, 2018 13:17
-
-
Save dnbaker/0fc1d4edbbdb24069eb063dc2559e4f5 to your computer and use it in GitHub Desktop.
SIMD-accelerated Murmur3 Finalizer and Wang 64-bit hash function implementations
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdio> | |
#include <cstdint> | |
#ifndef _VEC_H__ | |
# define NO_SLEEF | |
# define NO_BLAZE | |
# include "vec/vec.h" // Import vec.h, but disable blaze and sleef. | |
#endif // Uses https://github.com/dnbaker/vec for vectorization metaprogramming | |
#ifndef HAS_AVX_512 | |
# define HAS_AVX_512 (_FEATURE_AVX512F || _FEATURE_AVX512ER || _FEATURE_AVX512PF || _FEATURE_AVX512CD || __AVX512BW__ || __AVX512CD__ || __AVX512F__) | |
#endif | |
namespace hash { | |
using namespace std::literals; | |
using std::uint64_t; | |
using std::uint32_t; | |
using std::uint16_t; | |
using std::uint8_t; | |
using std::size_t; | |
using Space = vec::SIMDTypes<uint64_t>; | |
using Type = typename vec::SIMDTypes<uint64_t>::Type; | |
using VType = typename vec::SIMDTypes<uint64_t>::VType; | |
struct WangHash { | |
uint64_t operator()(uint64_t key) const { | |
key = (~key) + (key << 21); // key = (key << 21) - key - 1; | |
key = key ^ (key >> 24); | |
key = (key + (key << 3)) + (key << 8); // key * 265 | |
key = key ^ (key >> 14); | |
key = (key + (key << 2)) + (key << 4); // key * 21 | |
key = key ^ (key >> 28) | |
key = key + (key << 31); | |
return key; | |
} | |
Type operator()(Type element) const { | |
VType key = Space::add(Space::slli(element, 21), ~element); // key = (~key) + (key << 21); | |
key = Space::srli(key.simd_, 24) ^ key.simd_; //key ^ (key >> 24) | |
key = Space::add(Space::add(Space::slli(key.simd_, 3), Space::slli(key.simd_, 8)), key.simd_); // (key + (key << 3)) + (key << 8); | |
key = key.simd_ ^ Space::srli(key.simd_, 14); // key ^ (key >> 14); | |
key = Space::add(Space::add(Space::slli(key.simd_, 2), Space::slli(key.simd_, 4)), key.simd_); // (key + (key << 2)) + (key << 4); // key * 21 | |
key = key.simd_ ^ Space::srli(key.simd_, 28); // key ^ (key >> 28); | |
key = Space::add(Space::slli(key.simd_, 31), key.simd_); // key + (key << 31); | |
return key.simd_; | |
} | |
}; | |
struct MurFinHash { | |
uint64_t operator()(uint64_t key) const { | |
key ^= key >> 33; | |
key *= 0xff51afd7ed558ccd; | |
key ^= key >> 33; | |
key *= 0xc4ceb9fe1a85ec53; | |
key ^= key >> 33; | |
return key; | |
} | |
Type operator()(Type key) const { | |
return this->operator()(*((VType *)&key)); | |
} | |
Type operator()(VType key) const { | |
#if (HAS_AVX_512) | |
static const Type mul1 = Space::set1(0xff51afd7ed558ccd); | |
static const Type mul2 = Space::set1(0xc4ceb9fe1a85ec53); | |
#endif | |
#if !NDEBUG | |
auto save = key.arr_[0]; | |
#endif | |
key = Space::srli(key.simd_, 33) ^ key.simd_; // h ^= h >> 33; | |
#if (HAS_AVX_512) == 0 | |
key.for_each([](uint64_t &x) {x *= 0xff51afd7ed558ccd;}); | |
# else | |
key = Space::mullo(key.simd_, mul1); // h *= 0xff51afd7ed558ccd; | |
#endif | |
key = Space::srli(key.simd_, 33) ^ key.simd_; // h ^= h >> 33; | |
#if (HAS_AVX_512) == 0 | |
key.for_each([](uint64_t &x) {x *= 0xc4ceb9fe1a85ec53;}); | |
# else | |
key = Space::mullo(key.simd_, mul2); // h *= 0xc4ceb9fe1a85ec53; | |
#endif | |
key = Space::srli(key.simd_, 33) ^ key.simd_; // h ^= h >> 33; | |
assert(this->operator()(save) == key.arr_[0]); | |
return key.simd_; | |
} | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment