xref: /netbsd-src/external/bsd/jemalloc.old/include/jemalloc/internal/hash.h (revision 8e33eff89e26cf71871ead62f0d5063e1313c33a)
1*8e33eff8Schristos #ifndef JEMALLOC_INTERNAL_HASH_H
2*8e33eff8Schristos #define JEMALLOC_INTERNAL_HASH_H
3*8e33eff8Schristos 
4*8e33eff8Schristos #include "jemalloc/internal/assert.h"
5*8e33eff8Schristos 
6*8e33eff8Schristos /*
7*8e33eff8Schristos  * The following hash function is based on MurmurHash3, placed into the public
8*8e33eff8Schristos  * domain by Austin Appleby.  See https://github.com/aappleby/smhasher for
9*8e33eff8Schristos  * details.
10*8e33eff8Schristos  */
11*8e33eff8Schristos 
12*8e33eff8Schristos /******************************************************************************/
13*8e33eff8Schristos /* Internal implementation. */
14*8e33eff8Schristos static inline uint32_t
15*8e33eff8Schristos hash_rotl_32(uint32_t x, int8_t r) {
16*8e33eff8Schristos 	return ((x << r) | (x >> (32 - r)));
17*8e33eff8Schristos }
18*8e33eff8Schristos 
19*8e33eff8Schristos static inline uint64_t
20*8e33eff8Schristos hash_rotl_64(uint64_t x, int8_t r) {
21*8e33eff8Schristos 	return ((x << r) | (x >> (64 - r)));
22*8e33eff8Schristos }
23*8e33eff8Schristos 
24*8e33eff8Schristos static inline uint32_t
25*8e33eff8Schristos hash_get_block_32(const uint32_t *p, int i) {
26*8e33eff8Schristos 	/* Handle unaligned read. */
27*8e33eff8Schristos 	if (unlikely((uintptr_t)p & (sizeof(uint32_t)-1)) != 0) {
28*8e33eff8Schristos 		uint32_t ret;
29*8e33eff8Schristos 
30*8e33eff8Schristos 		memcpy(&ret, (const uint8_t *)(p + i), sizeof(uint32_t));
31*8e33eff8Schristos 		return ret;
32*8e33eff8Schristos 	}
33*8e33eff8Schristos 
34*8e33eff8Schristos 	return p[i];
35*8e33eff8Schristos }
36*8e33eff8Schristos 
37*8e33eff8Schristos static inline uint64_t
38*8e33eff8Schristos hash_get_block_64(const uint64_t *p, int i) {
39*8e33eff8Schristos 	/* Handle unaligned read. */
40*8e33eff8Schristos 	if (unlikely((uintptr_t)p & (sizeof(uint64_t)-1)) != 0) {
41*8e33eff8Schristos 		uint64_t ret;
42*8e33eff8Schristos 
43*8e33eff8Schristos 		memcpy(&ret, (const uint8_t *)(p + i), sizeof(uint64_t));
44*8e33eff8Schristos 		return ret;
45*8e33eff8Schristos 	}
46*8e33eff8Schristos 
47*8e33eff8Schristos 	return p[i];
48*8e33eff8Schristos }
49*8e33eff8Schristos 
50*8e33eff8Schristos static inline uint32_t
51*8e33eff8Schristos hash_fmix_32(uint32_t h) {
52*8e33eff8Schristos 	h ^= h >> 16;
53*8e33eff8Schristos 	h *= 0x85ebca6b;
54*8e33eff8Schristos 	h ^= h >> 13;
55*8e33eff8Schristos 	h *= 0xc2b2ae35;
56*8e33eff8Schristos 	h ^= h >> 16;
57*8e33eff8Schristos 
58*8e33eff8Schristos 	return h;
59*8e33eff8Schristos }
60*8e33eff8Schristos 
61*8e33eff8Schristos static inline uint64_t
62*8e33eff8Schristos hash_fmix_64(uint64_t k) {
63*8e33eff8Schristos 	k ^= k >> 33;
64*8e33eff8Schristos 	k *= KQU(0xff51afd7ed558ccd);
65*8e33eff8Schristos 	k ^= k >> 33;
66*8e33eff8Schristos 	k *= KQU(0xc4ceb9fe1a85ec53);
67*8e33eff8Schristos 	k ^= k >> 33;
68*8e33eff8Schristos 
69*8e33eff8Schristos 	return k;
70*8e33eff8Schristos }
71*8e33eff8Schristos 
72*8e33eff8Schristos static inline uint32_t
73*8e33eff8Schristos hash_x86_32(const void *key, int len, uint32_t seed) {
74*8e33eff8Schristos 	const uint8_t *data = (const uint8_t *) key;
75*8e33eff8Schristos 	const int nblocks = len / 4;
76*8e33eff8Schristos 
77*8e33eff8Schristos 	uint32_t h1 = seed;
78*8e33eff8Schristos 
79*8e33eff8Schristos 	const uint32_t c1 = 0xcc9e2d51;
80*8e33eff8Schristos 	const uint32_t c2 = 0x1b873593;
81*8e33eff8Schristos 
82*8e33eff8Schristos 	/* body */
83*8e33eff8Schristos 	{
84*8e33eff8Schristos 		const uint32_t *blocks = (const uint32_t *) (data + nblocks*4);
85*8e33eff8Schristos 		int i;
86*8e33eff8Schristos 
87*8e33eff8Schristos 		for (i = -nblocks; i; i++) {
88*8e33eff8Schristos 			uint32_t k1 = hash_get_block_32(blocks, i);
89*8e33eff8Schristos 
90*8e33eff8Schristos 			k1 *= c1;
91*8e33eff8Schristos 			k1 = hash_rotl_32(k1, 15);
92*8e33eff8Schristos 			k1 *= c2;
93*8e33eff8Schristos 
94*8e33eff8Schristos 			h1 ^= k1;
95*8e33eff8Schristos 			h1 = hash_rotl_32(h1, 13);
96*8e33eff8Schristos 			h1 = h1*5 + 0xe6546b64;
97*8e33eff8Schristos 		}
98*8e33eff8Schristos 	}
99*8e33eff8Schristos 
100*8e33eff8Schristos 	/* tail */
101*8e33eff8Schristos 	{
102*8e33eff8Schristos 		const uint8_t *tail = (const uint8_t *) (data + nblocks*4);
103*8e33eff8Schristos 
104*8e33eff8Schristos 		uint32_t k1 = 0;
105*8e33eff8Schristos 
106*8e33eff8Schristos 		switch (len & 3) {
107*8e33eff8Schristos 		case 3: k1 ^= tail[2] << 16;
108*8e33eff8Schristos 		case 2: k1 ^= tail[1] << 8;
109*8e33eff8Schristos 		case 1: k1 ^= tail[0]; k1 *= c1; k1 = hash_rotl_32(k1, 15);
110*8e33eff8Schristos 			k1 *= c2; h1 ^= k1;
111*8e33eff8Schristos 		}
112*8e33eff8Schristos 	}
113*8e33eff8Schristos 
114*8e33eff8Schristos 	/* finalization */
115*8e33eff8Schristos 	h1 ^= len;
116*8e33eff8Schristos 
117*8e33eff8Schristos 	h1 = hash_fmix_32(h1);
118*8e33eff8Schristos 
119*8e33eff8Schristos 	return h1;
120*8e33eff8Schristos }
121*8e33eff8Schristos 
122*8e33eff8Schristos UNUSED static inline void
123*8e33eff8Schristos hash_x86_128(const void *key, const int len, uint32_t seed,
124*8e33eff8Schristos     uint64_t r_out[2]) {
125*8e33eff8Schristos 	const uint8_t * data = (const uint8_t *) key;
126*8e33eff8Schristos 	const int nblocks = len / 16;
127*8e33eff8Schristos 
128*8e33eff8Schristos 	uint32_t h1 = seed;
129*8e33eff8Schristos 	uint32_t h2 = seed;
130*8e33eff8Schristos 	uint32_t h3 = seed;
131*8e33eff8Schristos 	uint32_t h4 = seed;
132*8e33eff8Schristos 
133*8e33eff8Schristos 	const uint32_t c1 = 0x239b961b;
134*8e33eff8Schristos 	const uint32_t c2 = 0xab0e9789;
135*8e33eff8Schristos 	const uint32_t c3 = 0x38b34ae5;
136*8e33eff8Schristos 	const uint32_t c4 = 0xa1e38b93;
137*8e33eff8Schristos 
138*8e33eff8Schristos 	/* body */
139*8e33eff8Schristos 	{
140*8e33eff8Schristos 		const uint32_t *blocks = (const uint32_t *) (data + nblocks*16);
141*8e33eff8Schristos 		int i;
142*8e33eff8Schristos 
143*8e33eff8Schristos 		for (i = -nblocks; i; i++) {
144*8e33eff8Schristos 			uint32_t k1 = hash_get_block_32(blocks, i*4 + 0);
145*8e33eff8Schristos 			uint32_t k2 = hash_get_block_32(blocks, i*4 + 1);
146*8e33eff8Schristos 			uint32_t k3 = hash_get_block_32(blocks, i*4 + 2);
147*8e33eff8Schristos 			uint32_t k4 = hash_get_block_32(blocks, i*4 + 3);
148*8e33eff8Schristos 
149*8e33eff8Schristos 			k1 *= c1; k1 = hash_rotl_32(k1, 15); k1 *= c2; h1 ^= k1;
150*8e33eff8Schristos 
151*8e33eff8Schristos 			h1 = hash_rotl_32(h1, 19); h1 += h2;
152*8e33eff8Schristos 			h1 = h1*5 + 0x561ccd1b;
153*8e33eff8Schristos 
154*8e33eff8Schristos 			k2 *= c2; k2 = hash_rotl_32(k2, 16); k2 *= c3; h2 ^= k2;
155*8e33eff8Schristos 
156*8e33eff8Schristos 			h2 = hash_rotl_32(h2, 17); h2 += h3;
157*8e33eff8Schristos 			h2 = h2*5 + 0x0bcaa747;
158*8e33eff8Schristos 
159*8e33eff8Schristos 			k3 *= c3; k3 = hash_rotl_32(k3, 17); k3 *= c4; h3 ^= k3;
160*8e33eff8Schristos 
161*8e33eff8Schristos 			h3 = hash_rotl_32(h3, 15); h3 += h4;
162*8e33eff8Schristos 			h3 = h3*5 + 0x96cd1c35;
163*8e33eff8Schristos 
164*8e33eff8Schristos 			k4 *= c4; k4 = hash_rotl_32(k4, 18); k4 *= c1; h4 ^= k4;
165*8e33eff8Schristos 
166*8e33eff8Schristos 			h4 = hash_rotl_32(h4, 13); h4 += h1;
167*8e33eff8Schristos 			h4 = h4*5 + 0x32ac3b17;
168*8e33eff8Schristos 		}
169*8e33eff8Schristos 	}
170*8e33eff8Schristos 
171*8e33eff8Schristos 	/* tail */
172*8e33eff8Schristos 	{
173*8e33eff8Schristos 		const uint8_t *tail = (const uint8_t *) (data + nblocks*16);
174*8e33eff8Schristos 		uint32_t k1 = 0;
175*8e33eff8Schristos 		uint32_t k2 = 0;
176*8e33eff8Schristos 		uint32_t k3 = 0;
177*8e33eff8Schristos 		uint32_t k4 = 0;
178*8e33eff8Schristos 
179*8e33eff8Schristos 		switch (len & 15) {
180*8e33eff8Schristos 		case 15: k4 ^= tail[14] << 16;	/*FALLTHROUGH*/
181*8e33eff8Schristos 		case 14: k4 ^= tail[13] << 8;	/*FALLTHROUGH*/
182*8e33eff8Schristos 		case 13: k4 ^= tail[12] << 0;
183*8e33eff8Schristos 			k4 *= c4; k4 = hash_rotl_32(k4, 18); k4 *= c1; h4 ^= k4;
184*8e33eff8Schristos 			/*FALLTHROUGH*/
185*8e33eff8Schristos 
186*8e33eff8Schristos 		case 12: k3 ^= (uint32_t)tail[11] << 24;	/*FALLTHROUGH*/
187*8e33eff8Schristos 		case 11: k3 ^= tail[10] << 16;	/*FALLTHROUGH*/
188*8e33eff8Schristos 		case 10: k3 ^= tail[ 9] << 8;	/*FALLTHROUGH*/
189*8e33eff8Schristos 		case  9: k3 ^= tail[ 8] << 0;
190*8e33eff8Schristos 			k3 *= c3; k3 = hash_rotl_32(k3, 17); k3 *= c4; h3 ^= k3;
191*8e33eff8Schristos 			/*FALLTHROUGH*/
192*8e33eff8Schristos 
193*8e33eff8Schristos 		case  8: k2 ^= (uint32_t)tail[ 7] << 24;	/*FALLTHROUGH*/
194*8e33eff8Schristos 		case  7: k2 ^= tail[ 6] << 16;	/*FALLTHROUGH*/
195*8e33eff8Schristos 		case  6: k2 ^= tail[ 5] << 8;	/*FALLTHROUGH*/
196*8e33eff8Schristos 		case  5: k2 ^= tail[ 4] << 0;
197*8e33eff8Schristos 			k2 *= c2; k2 = hash_rotl_32(k2, 16); k2 *= c3; h2 ^= k2;
198*8e33eff8Schristos 			/*FALLTHROUGH*/
199*8e33eff8Schristos 
200*8e33eff8Schristos 		case  4: k1 ^= (uint32_t)tail[ 3] << 24;	/*FALLTHROUGH*/
201*8e33eff8Schristos 		case  3: k1 ^= tail[ 2] << 16;	/*FALLTHROUGH*/
202*8e33eff8Schristos 		case  2: k1 ^= tail[ 1] << 8;	/*FALLTHROUGH*/
203*8e33eff8Schristos 		case  1: k1 ^= tail[ 0] << 0;
204*8e33eff8Schristos 			k1 *= c1; k1 = hash_rotl_32(k1, 15); k1 *= c2; h1 ^= k1;
205*8e33eff8Schristos 		}
206*8e33eff8Schristos 	}
207*8e33eff8Schristos 
208*8e33eff8Schristos 	/* finalization */
209*8e33eff8Schristos 	h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
210*8e33eff8Schristos 
211*8e33eff8Schristos 	h1 += h2; h1 += h3; h1 += h4;
212*8e33eff8Schristos 	h2 += h1; h3 += h1; h4 += h1;
213*8e33eff8Schristos 
214*8e33eff8Schristos 	h1 = hash_fmix_32(h1);
215*8e33eff8Schristos 	h2 = hash_fmix_32(h2);
216*8e33eff8Schristos 	h3 = hash_fmix_32(h3);
217*8e33eff8Schristos 	h4 = hash_fmix_32(h4);
218*8e33eff8Schristos 
219*8e33eff8Schristos 	h1 += h2; h1 += h3; h1 += h4;
220*8e33eff8Schristos 	h2 += h1; h3 += h1; h4 += h1;
221*8e33eff8Schristos 
222*8e33eff8Schristos 	r_out[0] = (((uint64_t) h2) << 32) | h1;
223*8e33eff8Schristos 	r_out[1] = (((uint64_t) h4) << 32) | h3;
224*8e33eff8Schristos }
225*8e33eff8Schristos 
226*8e33eff8Schristos UNUSED static inline void
227*8e33eff8Schristos hash_x64_128(const void *key, const int len, const uint32_t seed,
228*8e33eff8Schristos     uint64_t r_out[2]) {
229*8e33eff8Schristos 	const uint8_t *data = (const uint8_t *) key;
230*8e33eff8Schristos 	const int nblocks = len / 16;
231*8e33eff8Schristos 
232*8e33eff8Schristos 	uint64_t h1 = seed;
233*8e33eff8Schristos 	uint64_t h2 = seed;
234*8e33eff8Schristos 
235*8e33eff8Schristos 	const uint64_t c1 = KQU(0x87c37b91114253d5);
236*8e33eff8Schristos 	const uint64_t c2 = KQU(0x4cf5ad432745937f);
237*8e33eff8Schristos 
238*8e33eff8Schristos 	/* body */
239*8e33eff8Schristos 	{
240*8e33eff8Schristos 		const uint64_t *blocks = (const uint64_t *) (data);
241*8e33eff8Schristos 		int i;
242*8e33eff8Schristos 
243*8e33eff8Schristos 		for (i = 0; i < nblocks; i++) {
244*8e33eff8Schristos 			uint64_t k1 = hash_get_block_64(blocks, i*2 + 0);
245*8e33eff8Schristos 			uint64_t k2 = hash_get_block_64(blocks, i*2 + 1);
246*8e33eff8Schristos 
247*8e33eff8Schristos 			k1 *= c1; k1 = hash_rotl_64(k1, 31); k1 *= c2; h1 ^= k1;
248*8e33eff8Schristos 
249*8e33eff8Schristos 			h1 = hash_rotl_64(h1, 27); h1 += h2;
250*8e33eff8Schristos 			h1 = h1*5 + 0x52dce729;
251*8e33eff8Schristos 
252*8e33eff8Schristos 			k2 *= c2; k2 = hash_rotl_64(k2, 33); k2 *= c1; h2 ^= k2;
253*8e33eff8Schristos 
254*8e33eff8Schristos 			h2 = hash_rotl_64(h2, 31); h2 += h1;
255*8e33eff8Schristos 			h2 = h2*5 + 0x38495ab5;
256*8e33eff8Schristos 		}
257*8e33eff8Schristos 	}
258*8e33eff8Schristos 
259*8e33eff8Schristos 	/* tail */
260*8e33eff8Schristos 	{
261*8e33eff8Schristos 		const uint8_t *tail = (const uint8_t*)(data + nblocks*16);
262*8e33eff8Schristos 		uint64_t k1 = 0;
263*8e33eff8Schristos 		uint64_t k2 = 0;
264*8e33eff8Schristos 
265*8e33eff8Schristos 		switch (len & 15) {
266*8e33eff8Schristos 		case 15: k2 ^= ((uint64_t)(tail[14])) << 48; /* falls through */
267*8e33eff8Schristos 		case 14: k2 ^= ((uint64_t)(tail[13])) << 40; /* falls through */
268*8e33eff8Schristos 		case 13: k2 ^= ((uint64_t)(tail[12])) << 32; /* falls through */
269*8e33eff8Schristos 		case 12: k2 ^= ((uint64_t)(tail[11])) << 24; /* falls through */
270*8e33eff8Schristos 		case 11: k2 ^= ((uint64_t)(tail[10])) << 16; /* falls through */
271*8e33eff8Schristos 		case 10: k2 ^= ((uint64_t)(tail[ 9])) << 8;  /* falls through */
272*8e33eff8Schristos 		case  9: k2 ^= ((uint64_t)(tail[ 8])) << 0;
273*8e33eff8Schristos 			k2 *= c2; k2 = hash_rotl_64(k2, 33); k2 *= c1; h2 ^= k2;
274*8e33eff8Schristos 			/* falls through */
275*8e33eff8Schristos 		case  8: k1 ^= ((uint64_t)(tail[ 7])) << 56; /* falls through */
276*8e33eff8Schristos 		case  7: k1 ^= ((uint64_t)(tail[ 6])) << 48; /* falls through */
277*8e33eff8Schristos 		case  6: k1 ^= ((uint64_t)(tail[ 5])) << 40; /* falls through */
278*8e33eff8Schristos 		case  5: k1 ^= ((uint64_t)(tail[ 4])) << 32; /* falls through */
279*8e33eff8Schristos 		case  4: k1 ^= ((uint64_t)(tail[ 3])) << 24; /* falls through */
280*8e33eff8Schristos 		case  3: k1 ^= ((uint64_t)(tail[ 2])) << 16; /* falls through */
281*8e33eff8Schristos 		case  2: k1 ^= ((uint64_t)(tail[ 1])) << 8;  /* falls through */
282*8e33eff8Schristos 		case  1: k1 ^= ((uint64_t)(tail[ 0])) << 0;
283*8e33eff8Schristos 			k1 *= c1; k1 = hash_rotl_64(k1, 31); k1 *= c2; h1 ^= k1;
284*8e33eff8Schristos 		}
285*8e33eff8Schristos 	}
286*8e33eff8Schristos 
287*8e33eff8Schristos 	/* finalization */
288*8e33eff8Schristos 	h1 ^= len; h2 ^= len;
289*8e33eff8Schristos 
290*8e33eff8Schristos 	h1 += h2;
291*8e33eff8Schristos 	h2 += h1;
292*8e33eff8Schristos 
293*8e33eff8Schristos 	h1 = hash_fmix_64(h1);
294*8e33eff8Schristos 	h2 = hash_fmix_64(h2);
295*8e33eff8Schristos 
296*8e33eff8Schristos 	h1 += h2;
297*8e33eff8Schristos 	h2 += h1;
298*8e33eff8Schristos 
299*8e33eff8Schristos 	r_out[0] = h1;
300*8e33eff8Schristos 	r_out[1] = h2;
301*8e33eff8Schristos }
302*8e33eff8Schristos 
303*8e33eff8Schristos /******************************************************************************/
304*8e33eff8Schristos /* API. */
305*8e33eff8Schristos static inline void
306*8e33eff8Schristos hash(const void *key, size_t len, const uint32_t seed, size_t r_hash[2]) {
307*8e33eff8Schristos 	assert(len <= INT_MAX); /* Unfortunate implementation limitation. */
308*8e33eff8Schristos 
309*8e33eff8Schristos #if (LG_SIZEOF_PTR == 3 && !defined(JEMALLOC_BIG_ENDIAN))
310*8e33eff8Schristos 	hash_x64_128(key, (int)len, seed, (uint64_t *)r_hash);
311*8e33eff8Schristos #else
312*8e33eff8Schristos 	{
313*8e33eff8Schristos 		uint64_t hashes[2];
314*8e33eff8Schristos 		hash_x86_128(key, (int)len, seed, hashes);
315*8e33eff8Schristos 		r_hash[0] = (size_t)hashes[0];
316*8e33eff8Schristos 		r_hash[1] = (size_t)hashes[1];
317*8e33eff8Schristos 	}
318*8e33eff8Schristos #endif
319*8e33eff8Schristos }
320*8e33eff8Schristos 
321*8e33eff8Schristos #endif /* JEMALLOC_INTERNAL_HASH_H */
322