Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qhash.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// Copyright (C) 2021 Intel Corporation.
3// Copyright (C) 2012 Giuseppe D'Angelo <dangelog@gmail.com>.
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5
6// for rand_s, _CRT_RAND_S must be #defined before #including stdlib.h.
7// put it at the beginning so some indirect inclusion doesn't break it
8#ifndef _CRT_RAND_S
9#define _CRT_RAND_S
10#endif
11#include <stdlib.h>
12#include <stdint.h>
13
14#include "qhash.h"
15
16#ifdef truncate
17#undef truncate
18#endif
19
20#include <qbitarray.h>
21#include <qstring.h>
22#include <qglobal.h>
23#include <qbytearray.h>
24#include <qdatetime.h>
25#include <qbasicatomic.h>
26#include <qendian.h>
27#include <private/qrandom_p.h>
28#include <private/qsimd_p.h>
29
30#ifndef QT_BOOTSTRAPPED
31#include <qcoreapplication.h>
32#include <qrandom.h>
33#include <private/qlocale_tools_p.h>
34#endif // QT_BOOTSTRAPPED
35
36#include <array>
37#include <limits.h>
38
39#if defined(QT_NO_DEBUG) && !defined(NDEBUG)
40# define NDEBUG
41#endif
42#include <assert.h>
43
44#ifdef Q_CC_GNU
45# define Q_DECL_HOT_FUNCTION __attribute__((hot))
46#else
47# define Q_DECL_HOT_FUNCTION
48#endif
49
51
52// We assume that pointers and size_t have the same size. If that assumption should fail
53// on a platform the code selecting the different methods below needs to be fixed.
54static_assert(sizeof(size_t) == QT_POINTER_SIZE, "size_t and pointers have different size.");
55
56namespace {
57struct HashSeedStorage
58{
59 static constexpr int SeedCount = 2;
61
62#if !QT_SUPPORTS_INIT_PRIORITY || defined(QT_BOOTSTRAPPED)
63 constexpr HashSeedStorage() = default;
64#else
65 HashSeedStorage() { initialize(0); }
66#endif
67
68 enum State {
69 OverriddenByEnvironment = -1,
70 JustInitialized,
71 AlreadyInitialized
72 };
73 struct StateResult {
74 quintptr requestedSeed;
76 };
77
78 StateResult state(int which = -1);
79 Q_DECL_HOT_FUNCTION QHashSeed currentSeed(int which)
80 {
81 return { state(which).requestedSeed };
82 }
83
84 void resetSeed()
85 {
86 if (state().state < AlreadyInitialized)
87 return;
88
89 // update the public seed
91 seeds[0].storeRelaxed(sizeof(size_t) > sizeof(quint32)
93 }
94
95 void clearSeed()
96 {
97 state();
98 seeds[0].storeRelaxed(0); // always write (smaller code)
99 }
100
101private:
102 Q_DECL_COLD_FUNCTION Q_NEVER_INLINE StateResult initialize(int which) noexcept;
103};
104
105[[maybe_unused]] HashSeedStorage::StateResult HashSeedStorage::initialize(int which) noexcept
106{
107 StateResult result = { 0, OverriddenByEnvironment };
108#ifdef QT_BOOTSTRAPPED
109 Q_UNUSED(which);
110 Q_UNREACHABLE_RETURN(result);
111#else
112 // can't use qEnvironmentVariableIntValue (reentrancy)
113 const char *seedstr = getenv("QT_HASH_SEED");
114 if (seedstr) {
115 auto r = qstrntoll(seedstr, strlen(seedstr), 10);
116 if (r.used > 0 && size_t(r.used) == strlen(seedstr)) {
117 if (r.result) {
118 // can't use qWarning here (reentrancy)
119 fprintf(stderr, "QT_HASH_SEED: forced seed value is not 0; ignored.\n");
120 }
121
122 // we don't have to store to the seed, since it's pre-initialized by
123 // the compiler to zero
124 return result;
125 }
126 }
127
128 // update the full seed
129 auto x = qt_initial_random_value();
130 for (int i = 0; i < SeedCount; ++i) {
131 seeds[i].storeRelaxed(x.data[i]);
132 if (which == i)
133 result.requestedSeed = x.data[i];
134 }
135 result.state = JustInitialized;
136 return result;
137#endif
138}
139
140inline HashSeedStorage::StateResult HashSeedStorage::state(int which)
141{
142 constexpr quintptr BadSeed = quintptr(Q_UINT64_C(0x5555'5555'5555'5555));
143 StateResult result = { BadSeed, AlreadyInitialized };
144
145#if defined(QT_BOOTSTRAPPED)
146 result = { 0, OverriddenByEnvironment };
147#elif !QT_SUPPORTS_INIT_PRIORITY
148 // dynamic initialization
149 static auto once = [&]() {
150 result = initialize(which);
151 return true;
152 }();
153 Q_UNUSED(once);
154#endif
155
156 if (result.state == AlreadyInitialized && which >= 0)
157 return { seeds[which].loadRelaxed(), AlreadyInitialized };
158 return result;
159}
160} // unnamed namespace
161
162/*
163 The QHash seed itself.
164*/
165#ifdef Q_DECL_INIT_PRIORITY
166Q_DECL_INIT_PRIORITY(05)
167#else
168Q_CONSTINIT
169#endif
170static HashSeedStorage qt_qhash_seed;
171
172/*
173 * Hashing for memory segments is based on the public domain MurmurHash2 by
174 * Austin Appleby. See http://murmurhash.googlepages.com/
175 */
176#if QT_POINTER_SIZE == 4
178static inline uint murmurhash(const void *key, uint len, uint seed) noexcept
179{
180 // 'm' and 'r' are mixing constants generated offline.
181 // They're not really 'magic', they just happen to work well.
182
183 const unsigned int m = 0x5bd1e995;
184 const int r = 24;
185
186 // Initialize the hash to a 'random' value
187
188 unsigned int h = seed ^ len;
189
190 // Mix 4 bytes at a time into the hash
191
192 const unsigned char *data = reinterpret_cast<const unsigned char *>(key);
193 const unsigned char *end = data + (len & ~3);
194
195 while (data != end) {
196 size_t k;
197 memcpy(&k, data, sizeof(uint));
198
199 k *= m;
200 k ^= k >> r;
201 k *= m;
202
203 h *= m;
204 h ^= k;
205
206 data += 4;
207 }
208
209 // Handle the last few bytes of the input array
210 len &= 3;
211 if (len) {
212 unsigned int k = 0;
213 end += len;
214
215 while (data != end) {
216 k <<= 8;
217 k |= *data;
218 ++data;
219 }
220 h ^= k;
221 h *= m;
222 }
223
224 // Do a few final mixes of the hash to ensure the last few
225 // bytes are well-incorporated.
226
227 h ^= h >> 13;
228 h *= m;
229 h ^= h >> 15;
230
231 return h;
232}
233
234#else
236static inline uint64_t murmurhash(const void *key, uint64_t len, uint64_t seed) noexcept
237{
238 const uint64_t m = 0xc6a4a7935bd1e995ULL;
239 const int r = 47;
240
241 uint64_t h = seed ^ (len * m);
242
243 const unsigned char *data = reinterpret_cast<const unsigned char *>(key);
244 const unsigned char *end = data + (len & ~7ul);
245
246 while (data != end) {
247 uint64_t k;
248 memcpy(&k, data, sizeof(uint64_t));
249
250 k *= m;
251 k ^= k >> r;
252 k *= m;
253
254 h ^= k;
255 h *= m;
256
257 data += 8;
258 }
259
260 len &= 7;
261 if (len) {
262 // handle the last few bytes of input
263 size_t k = 0;
264 end += len;
265
266 while (data != end) {
267 k <<= 8;
268 k |= *data;
269 ++data;
270 }
271 h ^= k;
272 h *= m;
273 }
274
275 h ^= h >> r;
276 h *= m;
277 h ^= h >> r;
278
279 return h;
280}
281
282#endif
283
284#if QT_POINTER_SIZE == 8
285// This is an inlined version of the SipHash implementation that is
286// trying to avoid some memcpy's from uint64 to uint8[] and back.
287//
288
289// Use SipHash-1-2, which has similar performance characteristics as
290// stablehash() above, instead of the SipHash-2-4 default
291#define cROUNDS 1
292#define dROUNDS 2
293
294#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
295
296#define SIPROUND \
297 do { \
298 v0 += v1; \
299 v1 = ROTL(v1, 13); \
300 v1 ^= v0; \
301 v0 = ROTL(v0, 32); \
302 v2 += v3; \
303 v3 = ROTL(v3, 16); \
304 v3 ^= v2; \
305 v0 += v3; \
306 v3 = ROTL(v3, 21); \
307 v3 ^= v0; \
308 v2 += v1; \
309 v1 = ROTL(v1, 17); \
310 v1 ^= v2; \
311 v2 = ROTL(v2, 32); \
312 } while (0)
313
315static uint64_t siphash(const uint8_t *in, uint64_t inlen, uint64_t seed, uint64_t seed2)
316{
317 /* "somepseudorandomlygeneratedbytes" */
318 uint64_t v0 = 0x736f6d6570736575ULL;
319 uint64_t v1 = 0x646f72616e646f6dULL;
320 uint64_t v2 = 0x6c7967656e657261ULL;
321 uint64_t v3 = 0x7465646279746573ULL;
322 uint64_t b;
323 uint64_t k0 = seed;
324 uint64_t k1 = seed2;
325 int i;
326 const uint8_t *end = in + (inlen & ~7ULL);
327 const int left = inlen & 7;
328 b = inlen << 56;
329 v3 ^= k1;
330 v2 ^= k0;
331 v1 ^= k1;
332 v0 ^= k0;
333
334 for (; in != end; in += 8) {
335 uint64_t m = qFromUnaligned<uint64_t>(in);
336 v3 ^= m;
337
338 for (i = 0; i < cROUNDS; ++i)
339 SIPROUND;
340
341 v0 ^= m;
342 }
343
344
345#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 700
346 QT_WARNING_DISABLE_GCC("-Wimplicit-fallthrough")
347#endif
348 switch (left) {
349 case 7:
350 b |= ((uint64_t)in[6]) << 48;
351 case 6:
352 b |= ((uint64_t)in[5]) << 40;
353 case 5:
354 b |= ((uint64_t)in[4]) << 32;
355 case 4:
356 b |= ((uint64_t)in[3]) << 24;
357 case 3:
358 b |= ((uint64_t)in[2]) << 16;
359 case 2:
360 b |= ((uint64_t)in[1]) << 8;
361 case 1:
362 b |= ((uint64_t)in[0]);
363 break;
364 case 0:
365 break;
366 }
367
368 v3 ^= b;
369
370 for (i = 0; i < cROUNDS; ++i)
371 SIPROUND;
372
373 v0 ^= b;
374
375 v2 ^= 0xff;
376
377 for (i = 0; i < dROUNDS; ++i)
378 SIPROUND;
379
380 b = v0 ^ v1 ^ v2 ^ v3;
381 return b;
382}
383#else
384// This is a "SipHash" implementation adopted for 32bit platforms. It performs
385// basically the same operations as the 64bit version using 4 byte at a time
386// instead of 8.
387//
388// To make this work, we also need to change the constants for the mixing
389// rotations in ROTL. We're simply using half of the 64bit constants, rounded up
390// for odd numbers.
391//
392// For the v0-v4 constants, simply use the first four bytes of the 64 bit versions.
393//
394// Use SipHash-1-2, which has similar performance characteristics as
395// stablehash() above, instead of the SipHash-2-4 default
396#define cROUNDS 1
397#define dROUNDS 2
398
399#define ROTL(x, b) (uint32_t)(((x) << (b)) | ((x) >> (32 - (b))))
400
401#define SIPROUND \
402 do { \
403 v0 += v1; \
404 v1 = ROTL(v1, 7); \
405 v1 ^= v0; \
406 v0 = ROTL(v0, 16); \
407 v2 += v3; \
408 v3 = ROTL(v3, 8); \
409 v3 ^= v2; \
410 v0 += v3; \
411 v3 = ROTL(v3, 11); \
412 v3 ^= v0; \
413 v2 += v1; \
414 v1 = ROTL(v1, 9); \
415 v1 ^= v2; \
416 v2 = ROTL(v2, 16); \
417 } while (0)
418
420static uint siphash(const uint8_t *in, uint inlen, uint seed, uint seed2)
421{
422 /* "somepseudorandomlygeneratedbytes" */
423 uint v0 = 0x736f6d65U;
424 uint v1 = 0x646f7261U;
425 uint v2 = 0x6c796765U;
426 uint v3 = 0x74656462U;
427 uint b;
428 uint k0 = seed;
429 uint k1 = seed2;
430 int i;
431 const uint8_t *end = in + (inlen & ~3ULL);
432 const int left = inlen & 3;
433 b = inlen << 24;
434 v3 ^= k1;
435 v2 ^= k0;
436 v1 ^= k1;
437 v0 ^= k0;
438
439 for (; in != end; in += 4) {
440 uint m = qFromUnaligned<uint>(in);
441 v3 ^= m;
442
443 for (i = 0; i < cROUNDS; ++i)
444 SIPROUND;
445
446 v0 ^= m;
447 }
448
449#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 700
450 QT_WARNING_DISABLE_GCC("-Wimplicit-fallthrough")
451#endif
452 switch (left) {
453 case 3:
454 b |= ((uint)in[2]) << 16;
455 case 2:
456 b |= ((uint)in[1]) << 8;
457 case 1:
458 b |= ((uint)in[0]);
459 break;
460 case 0:
461 break;
462 }
463
464 v3 ^= b;
465
466 for (i = 0; i < cROUNDS; ++i)
467 SIPROUND;
468
469 v0 ^= b;
470
471 v2 ^= 0xff;
472
473 for (i = 0; i < dROUNDS; ++i)
474 SIPROUND;
475
476 b = v0 ^ v1 ^ v2 ^ v3;
477 return b;
478}
479#endif
480
481#if defined(__SANITIZE_ADDRESS__) || defined(__SANITIZE_THREAD__) // GCC
482# define QHASH_AES_SANITIZER_BUILD
483#elif __has_feature(address_sanitizer) || __has_feature(thread_sanitizer) // Clang
484# define QHASH_AES_SANITIZER_BUILD
485#endif
486
487// When built with a sanitizer, aeshash() is rightfully reported to have a
488// heap-buffer-overflow issue. However, we consider it to be safe in this
489// specific case and overcome the problem by correctly discarding the
490// out-of-range bits. To allow building the code with sanitizer,
491// QHASH_AES_SANITIZER_BUILD is used to disable aeshash() usage.
492#if QT_COMPILER_SUPPORTS_HERE(AES) && QT_COMPILER_SUPPORTS_HERE(SSE4_2) && \
493 !defined(QHASH_AES_SANITIZER_BUILD)
494# define AESHASH
495# define QT_FUNCTION_TARGET_STRING_AES_AVX2 "avx2,aes"
496# define QT_FUNCTION_TARGET_STRING_AES_AVX512 \
497 QT_FUNCTION_TARGET_STRING_ARCH_SKYLAKE_AVX512 "," \
498 QT_FUNCTION_TARGET_STRING_AES
499# define QT_FUNCTION_TARGET_STRING_VAES_AVX512 \
500 QT_FUNCTION_TARGET_STRING_ARCH_SKYLAKE_AVX512 "," \
501 QT_FUNCTION_TARGET_STRING_VAES
502# undef QHASH_AES_SANITIZER_BUILD
503# if QT_POINTER_SIZE == 8
504# define mm_set1_epz _mm_set1_epi64x
505# define mm_cvtsz_si128 _mm_cvtsi64_si128
506# define mm_cvtsi128_sz _mm_cvtsi128_si64
507# define mm256_set1_epz _mm256_set1_epi64x
508# else
509# define mm_set1_epz _mm_set1_epi32
510# define mm_cvtsz_si128 _mm_cvtsi32_si128
511# define mm_cvtsi128_sz _mm_cvtsi128_si32
512# define mm256_set1_epz _mm256_set1_epi32
513# endif
514
515namespace {
516 // This is inspired by the algorithm in the Go language. See:
517 // https://github.com/golang/go/blob/01b6cf09fc9f272d9db3d30b4c93982f4911d120/src/runtime/asm_amd64.s#L1105
518 // https://github.com/golang/go/blob/01b6cf09fc9f272d9db3d30b4c93982f4911d120/src/runtime/asm_386.s#L908
519 //
520 // Even though we're using the AESENC instruction from the CPU, this code
521 // is not encryption and this routine makes no claim to be
522 // cryptographically secure. We're simply using the instruction that performs
523 // the scrambling round (step 3 in [1]) because it's just very good at
524 // spreading the bits around.
525 //
526 // [1] https://en.wikipedia.org/wiki/Advanced_Encryption_Standard#High-level_description_of_the_algorithm
527
528 // hash 16 bytes, running 3 scramble rounds of AES on itself (like label "final1")
529 static void QT_FUNCTION_TARGET(AES) QT_VECTORCALL
530 hash16bytes(__m128i &state0, __m128i data)
531 {
532 state0 = _mm_xor_si128(state0, data);
533 state0 = _mm_aesenc_si128(state0, state0);
534 state0 = _mm_aesenc_si128(state0, state0);
535 state0 = _mm_aesenc_si128(state0, state0);
536 }
537
538 // hash twice 16 bytes, running 2 scramble rounds of AES on itself
539 static void QT_FUNCTION_TARGET(AES) QT_VECTORCALL
540 hash2x16bytes(__m128i &state0, __m128i &state1, const __m128i *src0, const __m128i *src1)
541 {
542 __m128i data0 = _mm_loadu_si128(src0);
543 __m128i data1 = _mm_loadu_si128(src1);
544 state0 = _mm_xor_si128(data0, state0);
545 state1 = _mm_xor_si128(data1, state1);
546 state0 = _mm_aesenc_si128(state0, state0);
547 state1 = _mm_aesenc_si128(state1, state1);
548 state0 = _mm_aesenc_si128(state0, state0);
549 state1 = _mm_aesenc_si128(state1, state1);
550 }
551
552 struct AESHashSeed
553 {
554 __m128i state0;
555 __m128i mseed2;
556 AESHashSeed(size_t seed, size_t seed2) QT_FUNCTION_TARGET(AES);
557 __m128i state1() const QT_FUNCTION_TARGET(AES);
558 __m256i state0_256() const QT_FUNCTION_TARGET(AES_AVX2)
559 { return _mm256_set_m128i(state1(), state0); }
560 };
561} // unnamed namespace
562
563Q_ALWAYS_INLINE AESHashSeed::AESHashSeed(size_t seed, size_t seed2)
564{
565 __m128i mseed = mm_cvtsz_si128(seed);
566 mseed2 = mm_set1_epz(seed2);
567
568 // mseed (epi16) = [ seed, seed >> 16, seed >> 32, seed >> 48, len, 0, 0, 0 ]
569 mseed = _mm_insert_epi16(mseed, short(seed), 4);
570 // mseed (epi16) = [ seed, seed >> 16, seed >> 32, seed >> 48, len, len, len, len ]
571 mseed = _mm_shufflehi_epi16(mseed, 0);
572
573 // merge with the process-global seed
574 __m128i key = _mm_xor_si128(mseed, mseed2);
575
576 // scramble the key
577 __m128i state0 = _mm_aesenc_si128(key, key);
578 this->state0 = state0;
579}
580
581Q_ALWAYS_INLINE __m128i AESHashSeed::state1() const
582{
583 {
584 // unlike the Go code, we don't have more per-process seed
585 __m128i state1 = _mm_aesenc_si128(state0, mseed2);
586 return state1;
587 }
588}
589
590static size_t QT_FUNCTION_TARGET(AES) QT_VECTORCALL
591aeshash128_16to32(__m128i state0, __m128i state1, const __m128i *src, const __m128i *srcend)
592{
593 {
594 if (src + 1 < srcend) {
595 // epilogue: between 16 and 31 bytes
596 hash2x16bytes(state0, state1, src, srcend - 1);
597 } else if (src != srcend) {
598 // epilogue: between 1 and 16 bytes, overlap with the end
599 __m128i data = _mm_loadu_si128(srcend - 1);
600 hash16bytes(state0, data);
601 }
602
603 // combine results:
604 state0 = _mm_xor_si128(state0, state1);
605 }
606
607 return mm_cvtsi128_sz(state0);
608}
609
610static size_t QT_FUNCTION_TARGET(AES) QT_VECTORCALL
611aeshash128_lt16(__m128i state0, const uchar *p, size_t len)
612{
613 if (len) {
614 // We're going to load 16 bytes and mask zero the part we don't care
615 // (the hash of a short string is different from the hash of a longer
616 // including NULLs at the end because the length is in the key)
617 // WARNING: this may produce valgrind warnings, but it's safe
618
619 constexpr quintptr PageSize = 4096;
620 __m128i data;
621
622 if ((quintptr(p) & (PageSize / 2)) == 0) {
623 // lower half of the page:
624 // load all 16 bytes and mask off the bytes past the end of the source
625 static const qint8 maskarray[] = {
626 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
627 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
628 };
629 __m128i mask = _mm_loadu_si128(reinterpret_cast<const __m128i *>(maskarray + 15 - len));
630 data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
631 data = _mm_and_si128(data, mask);
632 } else {
633 // upper half of the page:
634 // load 16 bytes ending at the data end, then shuffle them to the beginning
635 static const qint8 shufflecontrol[] = {
636 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
637 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
638 };
639 __m128i control = _mm_loadu_si128(reinterpret_cast<const __m128i *>(shufflecontrol + 15 - len));
640 data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p + len) - 1);
641 data = _mm_shuffle_epi8(data, control);
642 }
643
644 hash16bytes(state0, data);
645 }
646 return mm_cvtsi128_sz(state0);
647}
648
649static size_t QT_FUNCTION_TARGET(AES) QT_VECTORCALL
650aeshash128_ge32(__m128i state0, __m128i state1, const __m128i *src, const __m128i *srcend)
651{
652 // main loop: scramble two 16-byte blocks
653 for ( ; src + 2 < srcend; src += 2)
654 hash2x16bytes(state0, state1, src, src + 1);
655
656 return aeshash128_16to32(state0, state1, src, srcend);
657}
658
659# if QT_COMPILER_SUPPORTS_HERE(VAES)
660static size_t QT_FUNCTION_TARGET(ARCH_ICL) QT_VECTORCALL
661aeshash256_lt32_avx256(__m256i state0, const uchar *p, size_t len)
662{
663 __m128i state0_128 = _mm256_castsi256_si128(state0);
664 if (len) {
665 __mmask32 mask = _bzhi_u32(-1, unsigned(len));
666 __m256i data = _mm256_maskz_loadu_epi8(mask, p);
667 __m128i data0 = _mm256_castsi256_si128(data);
668 if (len >= sizeof(__m128i)) {
669 state0 = _mm256_xor_si256(state0, data);
670 state0 = _mm256_aesenc_epi128(state0, state0);
671 state0 = _mm256_aesenc_epi128(state0, state0);
672 // we're XOR'ing the two halves so we skip the third AESENC
673 // state0 = _mm256_aesenc_epi128(state0, state0);
674
675 // XOR the two halves and extract
676 __m128i low = _mm256_extracti128_si256(state0, 0);
677 __m128i high = _mm256_extracti128_si256(state0, 1);
678 state0_128 = _mm_xor_si128(low, high);
679 } else {
680 hash16bytes(state0_128, data0);
681 }
682 }
683 return mm_cvtsi128_sz(state0_128);
684}
685
686static size_t QT_FUNCTION_TARGET(VAES) QT_VECTORCALL
687aeshash256_ge32(__m256i state0, const uchar *p, size_t len)
688{
689 static const auto hash32bytes = [](__m256i &state0, __m256i data) QT_FUNCTION_TARGET(VAES) {
690 state0 = _mm256_xor_si256(state0, data);
691 state0 = _mm256_aesenc_epi128(state0, state0);
692 state0 = _mm256_aesenc_epi128(state0, state0);
693 state0 = _mm256_aesenc_epi128(state0, state0);
694 };
695
696 // hash twice 32 bytes, running 2 scramble rounds of AES on itself
697 const auto hash2x32bytes = [](__m256i &state0, __m256i &state1, const __m256i *src0,
698 const __m256i *src1) QT_FUNCTION_TARGET(VAES) {
699 __m256i data0 = _mm256_loadu_si256(src0);
700 __m256i data1 = _mm256_loadu_si256(src1);
701 state0 = _mm256_xor_si256(data0, state0);
702 state1 = _mm256_xor_si256(data1, state1);
703 state0 = _mm256_aesenc_epi128(state0, state0);
704 state1 = _mm256_aesenc_epi128(state1, state1);
705 state0 = _mm256_aesenc_epi128(state0, state0);
706 state1 = _mm256_aesenc_epi128(state1, state1);
707 };
708
709 const __m256i *src = reinterpret_cast<const __m256i *>(p);
710 const __m256i *srcend = reinterpret_cast<const __m256i *>(p + len);
711
712 __m256i state1 = _mm256_aesenc_epi128(state0, mm256_set1_epz(len));
713
714 // main loop: scramble two 32-byte blocks
715 for ( ; src + 2 < srcend; src += 2)
716 hash2x32bytes(state0, state1, src, src + 1);
717
718 if (src + 1 < srcend) {
719 // epilogue: between 32 and 31 bytes
720 hash2x32bytes(state0, state1, src, srcend - 1);
721 } else if (src != srcend) {
722 // epilogue: between 1 and 32 bytes, overlap with the end
723 __m256i data = _mm256_loadu_si256(srcend - 1);
724 hash32bytes(state0, data);
725 }
726
727 // combine results:
728 state0 = _mm256_xor_si256(state0, state1);
729
730 // XOR the two halves and extract
731 __m128i low = _mm256_extracti128_si256(state0, 0);
732 __m128i high = _mm256_extracti128_si256(state0, 1);
733 return mm_cvtsi128_sz(_mm_xor_si128(low, high));
734}
735
736static size_t QT_FUNCTION_TARGET(VAES)
737aeshash256(const uchar *p, size_t len, size_t seed, size_t seed2) noexcept
738{
739 AESHashSeed state(seed, seed2);
740 auto src = reinterpret_cast<const __m128i *>(p);
741 const auto srcend = reinterpret_cast<const __m128i *>(p + len);
742
743 if (len < sizeof(__m128i))
744 return aeshash128_lt16(state.state0, p, len);
745
746 if (len <= sizeof(__m256i))
747 return aeshash128_16to32(state.state0, state.state1(), src, srcend);
748
749 return aeshash256_ge32(state.state0_256(), p, len);
750}
751
752static size_t QT_FUNCTION_TARGET(VAES_AVX512)
753aeshash256_avx256(const uchar *p, size_t len, size_t seed, size_t seed2) noexcept
754{
755 AESHashSeed state(seed, seed2);
756 if (len <= sizeof(__m256i))
757 return aeshash256_lt32_avx256(state.state0_256(), p, len);
758
759 return aeshash256_ge32(state.state0_256(), p, len);
760}
761# endif // VAES
762
763static size_t QT_FUNCTION_TARGET(AES)
764aeshash128(const uchar *p, size_t len, size_t seed, size_t seed2) noexcept
765{
766 AESHashSeed state(seed, seed2);
767 auto src = reinterpret_cast<const __m128i *>(p);
768 const auto srcend = reinterpret_cast<const __m128i *>(p + len);
769
770 if (len < sizeof(__m128i))
771 return aeshash128_lt16(state.state0, p, len);
772
773 if (len <= sizeof(__m256i))
774 return aeshash128_16to32(state.state0, state.state1(), src, srcend);
775
776 return aeshash128_ge32(state.state0, state.state1(), src, srcend);
777}
778
779static size_t aeshash(const uchar *p, size_t len, size_t seed, size_t seed2) noexcept
780{
781# if QT_COMPILER_SUPPORTS_HERE(VAES)
782 if (qCpuHasFeature(VAES)) {
783 if (qCpuHasFeature(AVX512VL))
784 return aeshash256_avx256(p, len, seed, seed2);
785 return aeshash256(p, len, seed, seed2);
786 }
787# endif
788 return aeshash128(p, len, seed, seed2);
789}
790#endif // x86 AESNI
791
792#if defined(Q_PROCESSOR_ARM) && QT_COMPILER_SUPPORTS_HERE(AES) && !defined(QHASH_AES_SANITIZER_BUILD) && !defined(QT_BOOTSTRAPPED)
794static size_t aeshash(const uchar *p, size_t len, size_t seed, size_t seed2) noexcept
795{
796 uint8x16_t key;
797# if QT_POINTER_SIZE == 8
798 uint64x2_t vseed = vcombine_u64(vcreate_u64(seed), vcreate_u64(seed2));
799 key = vreinterpretq_u8_u64(vseed);
800# else
801
802 uint32x2_t vseed = vmov_n_u32(seed);
803 vseed = vset_lane_u32(seed2, vseed, 1);
804 key = vreinterpretq_u8_u32(vcombine_u32(vseed, vseed));
805# endif
806
807 // Compared to x86 AES, ARM splits each round into two instructions
808 // and includes the pre-xor instead of the post-xor.
809 const auto hash16bytes = [](uint8x16_t &state0, uint8x16_t data) {
810 auto state1 = state0;
811 state0 = vaeseq_u8(state0, data);
812 state0 = vaesmcq_u8(state0);
813 auto state2 = state0;
814 state0 = vaeseq_u8(state0, state1);
815 state0 = vaesmcq_u8(state0);
816 auto state3 = state0;
817 state0 = vaeseq_u8(state0, state2);
818 state0 = vaesmcq_u8(state0);
819 state0 = veorq_u8(state0, state3);
820 };
821
822 uint8x16_t state0 = key;
823
824 if (len < 8)
825 goto lt8;
826 if (len < 16)
827 goto lt16;
828 if (len < 32)
829 goto lt32;
830
831 // rounds of 32 bytes
832 {
833 // Make state1 = ~state0:
834 uint8x16_t state1 = veorq_u8(state0, vdupq_n_u8(255));
835
836 // do simplified rounds of 32 bytes: unlike the Go code, we only
837 // scramble twice and we keep 256 bits of state
838 const auto *e = p + len - 31;
839 while (p < e) {
840 uint8x16_t data0 = vld1q_u8(p);
841 uint8x16_t data1 = vld1q_u8(p + 16);
842 auto oldstate0 = state0;
843 auto oldstate1 = state1;
844 state0 = vaeseq_u8(state0, data0);
845 state1 = vaeseq_u8(state1, data1);
846 state0 = vaesmcq_u8(state0);
847 state1 = vaesmcq_u8(state1);
848 auto laststate0 = state0;
849 auto laststate1 = state1;
850 state0 = vaeseq_u8(state0, oldstate0);
851 state1 = vaeseq_u8(state1, oldstate1);
852 state0 = vaesmcq_u8(state0);
853 state1 = vaesmcq_u8(state1);
854 state0 = veorq_u8(state0, laststate0);
855 state1 = veorq_u8(state1, laststate1);
856 p += 32;
857 }
858 state0 = veorq_u8(state0, state1);
859 }
860 len &= 0x1f;
861
862 // do we still have 16 or more bytes?
863 if (len & 0x10) {
864lt32:
865 uint8x16_t data = vld1q_u8(p);
866 hash16bytes(state0, data);
867 p += 16;
868 }
869 len &= 0xf;
870
871 if (len & 0x08) {
872lt16:
873 uint8x8_t data8 = vld1_u8(p);
874 uint8x16_t data = vcombine_u8(data8, vdup_n_u8(0));
875 hash16bytes(state0, data);
876 p += 8;
877 }
878 len &= 0x7;
879
880lt8:
881 if (len) {
882 // load the last chunk of data
883 // We're going to load 8 bytes and mask zero the part we don't care
884 // (the hash of a short string is different from the hash of a longer
885 // including NULLs at the end because the length is in the key)
886 // WARNING: this may produce valgrind warnings, but it's safe
887
888 uint8x8_t data8;
889
890 if (Q_LIKELY(quintptr(p + 8) & 0xff8)) {
891 // same page, we definitely can't fault:
892 // load all 8 bytes and mask off the bytes past the end of the source
893 static const qint8 maskarray[] = {
894 -1, -1, -1, -1, -1, -1, -1,
895 0, 0, 0, 0, 0, 0, 0,
896 };
897 uint8x8_t mask = vld1_u8(reinterpret_cast<const quint8 *>(maskarray) + 7 - len);
898 data8 = vld1_u8(p);
899 data8 = vand_u8(data8, mask);
900 } else {
901 // too close to the end of the page, it could fault:
902 // load 8 bytes ending at the data end, then shuffle them to the beginning
903 static const qint8 shufflecontrol[] = {
904 1, 2, 3, 4, 5, 6, 7,
905 -1, -1, -1, -1, -1, -1, -1,
906 };
907 uint8x8_t control = vld1_u8(reinterpret_cast<const quint8 *>(shufflecontrol) + 7 - len);
908 data8 = vld1_u8(p - 8 + len);
909 data8 = vtbl1_u8(data8, control);
910 }
911 uint8x16_t data = vcombine_u8(data8, vdup_n_u8(0));
912 hash16bytes(state0, data);
913 }
914
915 // extract state0
916# if QT_POINTER_SIZE == 8
917 return vgetq_lane_u64(vreinterpretq_u64_u8(state0), 0);
918# else
919 return vgetq_lane_u32(vreinterpretq_u32_u8(state0), 0);
920# endif
921}
922#endif
923
924size_t qHashBits(const void *p, size_t size, size_t seed) noexcept
925{
926#ifdef QT_BOOTSTRAPPED
927 // the seed is always 0 in bootstrapped mode (no seed generation code),
928 // so help the compiler do dead code elimination
929 seed = 0;
930#endif
931 // mix in the length as a secondary seed. For seed == 0, seed2 must be
932 // size, to match what we used to do prior to Qt 6.2.
933 size_t seed2 = size;
934 if (seed)
935 seed2 = qt_qhash_seed.currentSeed(1);
936#ifdef AESHASH
937 if (seed && qCpuHasFeature(AES) && qCpuHasFeature(SSE4_2))
938 return aeshash(reinterpret_cast<const uchar *>(p), size, seed, seed2);
939#elif defined(Q_PROCESSOR_ARM) && QT_COMPILER_SUPPORTS_HERE(AES) && !defined(QHASH_AES_SANITIZER_BUILD) && !defined(QT_BOOTSTRAPPED)
940# if defined(Q_OS_LINUX)
941 // Do specific runtime-only check as Yocto hard enables Crypto extension for
942 // all armv8 configs
943 if (seed && (qCpuFeatures() & CpuFeatureAES))
944# else
945 if (seed && qCpuHasFeature(AES))
946# endif
947 return aeshash(reinterpret_cast<const uchar *>(p), size, seed, seed2);
948#endif
949
950 if (size <= QT_POINTER_SIZE)
951 return murmurhash(p, size, seed);
952
953 return siphash(reinterpret_cast<const uchar *>(p), size, seed, seed2);
954}
955
956size_t qHash(QByteArrayView key, size_t seed) noexcept
957{
958 return qHashBits(key.constData(), size_t(key.size()), seed);
959}
960
961size_t qHash(QStringView key, size_t seed) noexcept
962{
963 return qHashBits(key.data(), key.size()*sizeof(QChar), seed);
964}
965
966size_t qHash(const QBitArray &bitArray, size_t seed) noexcept
967{
968 qsizetype m = bitArray.d.size() - 1;
969 size_t result = qHashBits(reinterpret_cast<const uchar *>(bitArray.d.constData()), size_t(qMax(0, m)), seed);
970
971 // deal with the last 0 to 7 bits manually, because we can't trust that
972 // the padding is initialized to 0 in bitArray.d
973 qsizetype n = bitArray.size();
974 if (n & 0x7)
975 result = ((result << 4) + bitArray.d.at(m)) & ((1 << n) - 1);
976 return result;
977}
978
979size_t qHash(QLatin1StringView key, size_t seed) noexcept
980{
981 return qHashBits(reinterpret_cast<const uchar *>(key.data()), size_t(key.size()), seed);
982}
983
1038{
1039 return qt_qhash_seed.currentSeed(0);
1040}
1041
1052{
1053 qt_qhash_seed.clearSeed();
1054}
1055
1072{
1073 qt_qhash_seed.resetSeed();
1074}
1075
1076#if QT_DEPRECATED_SINCE(6,6)
1088int qGlobalQHashSeed()
1089{
1090 return int(QHashSeed::globalSeed() & INT_MAX);
1091}
1092
1117void qSetGlobalQHashSeed(int newSeed)
1118{
1119 if (Q_LIKELY(newSeed == 0 || newSeed == -1)) {
1120 if (newSeed == 0)
1122 else
1124 } else {
1125 // can't use qWarning here (reentrancy)
1126 fprintf(stderr, "qSetGlobalQHashSeed: forced seed value is not 0; ignoring call\n");
1127 }
1128}
1129#endif // QT_DEPRECATED_SINCE(6,6)
1130
1146uint qt_hash(QStringView key, uint chained) noexcept
1147{
1148 auto n = key.size();
1149 auto p = key.utf16();
1150
1151 uint h = chained;
1152
1153 while (n--) {
1154 h = (h << 4) + *p++;
1155 h ^= (h & 0xf0000000) >> 23;
1156 h &= 0x0fffffff;
1157 }
1158 return h;
1159}
1160
1426size_t qHash(double key, size_t seed) noexcept
1427{
1428 // ensure -0 gets mapped to 0
1429 key += 0.0;
1430 if constexpr (sizeof(double) == sizeof(size_t)) {
1431 size_t k;
1432 memcpy(&k, &key, sizeof(double));
1433 return QHashPrivate::hash(k, seed);
1434 } else {
1435 return murmurhash(&key, sizeof(key), seed);
1436 }
1437}
1438
1439#if !defined(Q_OS_DARWIN) || defined(Q_QDOC)
1445size_t qHash(long double key, size_t seed) noexcept
1446{
1447 // ensure -0 gets mapped to 0
1448 key += static_cast<long double>(0.0);
1449 if constexpr (sizeof(long double) == sizeof(size_t)) {
1450 size_t k;
1451 memcpy(&k, &key, sizeof(long double));
1452 return QHashPrivate::hash(k, seed);
1453 } else {
1454 return murmurhash(&key, sizeof(key), seed);
1455 }
1456}
1457#endif
1458
3857#ifdef QT_HAS_CONSTEXPR_BITOPS
3858namespace QHashPrivate {
3859static_assert(qPopulationCount(SpanConstants::NEntries) == 1,
3860 "NEntries must be a power of 2 for bucketForHash() to work.");
3861
3862// ensure the size of a Span does not depend on the template parameters
3863using Node1 = Node<int, int>;
3864static_assert(sizeof(Span<Node1>) == sizeof(Span<Node<char, void *>>));
3865static_assert(sizeof(Span<Node1>) == sizeof(Span<Node<qsizetype, QHashDummyValue>>));
3866static_assert(sizeof(Span<Node1>) == sizeof(Span<Node<QString, QVariant>>));
3867static_assert(sizeof(Span<Node1>) > SpanConstants::NEntries);
3868static_assert(qNextPowerOfTwo(sizeof(Span<Node1>)) == SpanConstants::NEntries * 2);
3869
3870// ensure allocations are always a power of two, at a minimum NEntries,
3871// obeying the fomula
3872// qNextPowerOfTwo(2 * N);
3873// without overflowing
3874static constexpr size_t NEntries = SpanConstants::NEntries;
3875static_assert(GrowthPolicy::bucketsForCapacity(1) == NEntries);
3876static_assert(GrowthPolicy::bucketsForCapacity(NEntries / 2 + 0) == NEntries);
3877static_assert(GrowthPolicy::bucketsForCapacity(NEntries / 2 + 1) == 2 * NEntries);
3878static_assert(GrowthPolicy::bucketsForCapacity(NEntries * 1 - 1) == 2 * NEntries);
3879static_assert(GrowthPolicy::bucketsForCapacity(NEntries * 1 + 0) == 4 * NEntries);
3880static_assert(GrowthPolicy::bucketsForCapacity(NEntries * 1 + 1) == 4 * NEntries);
3881static_assert(GrowthPolicy::bucketsForCapacity(NEntries * 2 - 1) == 4 * NEntries);
3882static_assert(GrowthPolicy::bucketsForCapacity(NEntries * 2 + 0) == 8 * NEntries);
3883static_assert(GrowthPolicy::bucketsForCapacity(SIZE_MAX / 4) == SIZE_MAX / 2 + 1);
3884static_assert(GrowthPolicy::bucketsForCapacity(SIZE_MAX / 2) == SIZE_MAX);
3885static_assert(GrowthPolicy::bucketsForCapacity(SIZE_MAX) == SIZE_MAX);
3886}
3887#endif
3888
Definition lalr.h:137
void storeRelaxed(T newValue) noexcept
\inmodule QtCore
Definition qbitarray.h:13
\inmodule QtCore
Definition qchar.h:48
size_t qHash(double key, size_t seed) noexcept
Definition qhash.cpp:1426
size_t qHash(long double key, size_t seed) noexcept
Definition qhash.cpp:1445
\inmodule QtCore \reentrant
Definition qrandom.h:21
static Q_DECL_CONST_FUNCTION QRandomGenerator * system()
\threadsafe
Definition qrandom.h:270
quint32 generate()
Generates a 32-bit random quantity and returns it.
Definition qrandom.h:48
quint64 generate64()
Generates a 64-bit random quantity and returns it.
Definition qrandom.h:53
\inmodule QtCore
Definition qstringview.h:76
double e
else opt state
[0]
constexpr size_t bucketsForCapacity(size_t requestedCapacity) noexcept
Definition qhash.h:417
Q_DECL_CONST_FUNCTION constexpr size_t hash(size_t key, size_t seed) noexcept
Combined button and popup list for selecting options.
Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR uint qPopulationCount(quint32 v) noexcept
#define Q_BASIC_ATOMIC_INITIALIZER(a)
#define Q_NEVER_INLINE
#define Q_LIKELY(x)
#define Q_DECL_COLD_FUNCTION
#define QT_WARNING_DISABLE_GCC(text)
#define Q_ALWAYS_INLINE
static bool initialize()
Definition qctf.cpp:67
size_t qHashBits(const void *p, size_t size, size_t seed) noexcept
Definition qhash.cpp:924
#define dROUNDS
Definition qhash.cpp:397
Q_NEVER_INLINE static Q_DECL_HOT_FUNCTION uint siphash(const uint8_t *in, uint inlen, uint seed, uint seed2)
Definition qhash.cpp:420
Q_NEVER_INLINE static Q_DECL_HOT_FUNCTION uint64_t murmurhash(const void *key, uint64_t len, uint64_t seed) noexcept
Definition qhash.cpp:236
static Q_CONSTINIT HashSeedStorage qt_qhash_seed
Definition qhash.cpp:170
#define cROUNDS
Definition qhash.cpp:396
size_t qHash(QByteArrayView key, size_t seed) noexcept
Definition qhash.cpp:956
#define SIPROUND
Definition qhash.cpp:401
#define Q_DECL_HOT_FUNCTION
Definition qhash.cpp:47
uint qt_hash(QStringView key, uint chained) noexcept
Definition qhash.cpp:1146
QSimpleParsedNumber< qlonglong > qstrntoll(const char *begin, qsizetype size, int base)
constexpr quint32 qNextPowerOfTwo(quint32 v)
Definition qmath.h:335
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLint GLfloat GLfloat GLfloat v2
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
const GLfloat * m
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLuint GLuint end
GLenum src
GLint left
GLint GLfloat v0
GLint GLfloat GLfloat v1
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLfloat GLfloat GLfloat GLfloat v3
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLfloat n
GLfloat GLfloat GLfloat GLfloat h
GLenum GLsizei len
GLuint in
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
#define QT_POINTER_SIZE
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
QRandomGenerator::InitialRandomData qt_initial_random_value() noexcept
Definition qrandom.cpp:1287
#define QT_VECTORCALL
Definition qsimd.h:128
#define qCpuHasFeature(feature)
Definition qsimd_p.h:378
#define QT_FUNCTION_TARGET(x)
Definition qsimd_p.h:133
static uint64_t qCpuFeatures()
Definition qsimd_p.h:364
#define k0
#define k1
#define Q_UNUSED(x)
#define Q_UINT64_C(c)
Definition qtypes.h:53
unsigned int quint32
Definition qtypes.h:45
unsigned char uchar
Definition qtypes.h:27
size_t quintptr
Definition qtypes.h:72
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned int uint
Definition qtypes.h:29
QT_BEGIN_NAMESPACE typedef signed char qint8
Definition qtypes.h:40
unsigned char quint8
Definition qtypes.h:41
QRandomGenerator generator(sseq)
static constexpr size_t NEntries
Definition qhash.h:223
\inmodule QtCore
static Q_CORE_EXPORT void setDeterministicGlobalSeed()
\threadsafe
Definition qhash.cpp:1051
static Q_CORE_EXPORT void resetRandomGlobalSeed()
\threadsafe
Definition qhash.cpp:1071
static Q_CORE_EXPORT QHashSeed globalSeed() noexcept
\threadsafe
Definition qhash.cpp:1037