4#include <cuda/std/cstdint>
9__host__ __device__
constexpr uint64_t
splitmix64(uint64_t value)
noexcept {
11 value *= 0xbf58476d1ce4e5b9ULL;
13 value *= 0x94d049bb133111ebULL;
14 return value ^ (value >> 31);
18constexpr uint64_t
seed = 42;
21__host__ __device__
constexpr uint64_t
hash_kmer(uint64_t packed_kmer)
noexcept {
26template <
size_t BucketCount>
27__host__ __device__
constexpr size_t bucket_of(uint64_t hash)
noexcept {
28 static_assert(BucketCount != 0 && (BucketCount & (BucketCount - 1)) == 0);
29 return hash & (BucketCount - 1);
33constexpr uint64_t
PRIME64_1 = 11400714785074694791ULL;
34constexpr uint64_t
PRIME64_2 = 14029467366897019727ULL;
35constexpr uint64_t
PRIME64_3 = 1609587929392839161ULL;
36constexpr uint64_t
PRIME64_4 = 9650029242287828579ULL;
37constexpr uint64_t
PRIME64_5 = 2870177450012600261ULL;
40constexpr __host__ __device__ __forceinline__ uint64_t
rotl64(uint64_t x, int8_t r) {
41 return cuda::std::rotl(x,
static_cast<int>(r));
46__host__ __device__ __forceinline__ T
load_chunk(
const uint8_t* data, uint64_t index) {
48 memcpy(&chunk, data + index *
sizeof(T),
sizeof(T));
53constexpr __host__ __device__ __forceinline__ uint64_t
finalize(uint64_t h) {
63__host__ __device__
inline uint64_t
xxhash64(
const uint8_t* bytes, uint64_t size, uint64_t
seed) {
69 uint64_t limit = size - 32;
76 const uint64_t pipeline_offset = offset / 8;
77 v1 += load_chunk<uint64_t>(bytes, pipeline_offset + 0) *
PRIME64_2;
80 v2 += load_chunk<uint64_t>(bytes, pipeline_offset + 1) *
PRIME64_2;
83 v3 += load_chunk<uint64_t>(bytes, pipeline_offset + 2) *
PRIME64_2;
86 v4 += load_chunk<uint64_t>(bytes, pipeline_offset + 3) *
PRIME64_2;
90 }
while (offset <= limit);
124 if ((size % 32) >= 8) {
125 for (; offset <= size - 8; offset += 8) {
126 uint64_t k1 = load_chunk<uint64_t>(bytes, offset / 8) *
PRIME64_2;
134 if ((size % 8) >= 4) {
135 for (; offset <= size - 4; offset += 4) {
136 h64 ^= (load_chunk<uint32_t>(bytes, offset / 4) & 0xffffffffULL) *
PRIME64_1;
143 while (offset < size) {
144 h64 ^= (bytes[offset] & 0xff) *
PRIME64_5;
155__host__ __device__
inline uint64_t
xxhash64(
const T& key, uint64_t
seed = 0) {
156 return xxhash64(
reinterpret_cast<const uint8_t*
>(&key),
sizeof(T),
seed);
constexpr uint64_t PRIME64_3
constexpr uint64_t PRIME64_1
xxHash-64 round primes.
__host__ __device__ __forceinline__ T load_chunk(const uint8_t *data, uint64_t index)
Loads a chunk of type T from data at byte offset index*sizeof(T).
__host__ __device__ constexpr uint64_t splitmix64(uint64_t value) noexcept
SplitMix64 finalizer, applied to a packed k-mer XOR the domain seed.
constexpr uint64_t seed
Domain separation constant folded into every packed k-mer before hashing.
__host__ __device__ uint64_t xxhash64(const uint8_t *bytes, uint64_t size, uint64_t seed)
Computes xxHash-64 over a byte range without allocating or copying it.
constexpr __host__ __device__ __forceinline__ uint64_t finalize(uint64_t h)
Applies the xxHash-64 final mixing (avalanche) step.
__host__ __device__ constexpr uint64_t hash_kmer(uint64_t packed_kmer) noexcept
Hashes a canonical packed k-mer into the value space used by DDL registers.
constexpr uint64_t PRIME64_2
constexpr __host__ __device__ __forceinline__ uint64_t rotl64(uint64_t x, int8_t r)
Rotates x left by r bits.
constexpr uint64_t PRIME64_5
constexpr uint64_t PRIME64_4
__host__ __device__ constexpr size_t bucket_of(uint64_t hash) noexcept
Selects the register bucket for hash given a power-of-two BucketCount.