Skip to content

Instantly share code, notes, and snippets.

@dnbaker
Last active June 16, 2018 13:17
Show Gist options
  • Save dnbaker/0fc1d4edbbdb24069eb063dc2559e4f5 to your computer and use it in GitHub Desktop.
Save dnbaker/0fc1d4edbbdb24069eb063dc2559e4f5 to your computer and use it in GitHub Desktop.
SIMD-accelerated Murmur3 Finalizer and Wang 64-bit hash function implementations
#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