Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * pg_bitutils.c
4 : : * Miscellaneous functions for bit-wise operations.
5 : : *
6 : : * Copyright (c) 2019-2024, PostgreSQL Global Development Group
7 : : *
8 : : * IDENTIFICATION
9 : : * src/port/pg_bitutils.c
10 : : *
11 : : *-------------------------------------------------------------------------
12 : : */
13 : : #include "c.h"
14 : :
15 : : #ifdef HAVE__GET_CPUID
16 : : #include <cpuid.h>
17 : : #endif
18 : : #ifdef HAVE__CPUID
19 : : #include <intrin.h>
20 : : #endif
21 : :
22 : : #include "port/pg_bitutils.h"
23 : :
24 : :
25 : : /*
26 : : * Array giving the position of the left-most set bit for each possible
27 : : * byte value. We count the right-most position as the 0th bit, and the
28 : : * left-most the 7th bit. The 0th entry of the array should not be used.
29 : : *
30 : : * Note: this is not used by the functions in pg_bitutils.h when
31 : : * HAVE__BUILTIN_CLZ is defined, but we provide it anyway, so that
32 : : * extensions possibly compiled with a different compiler can use it.
33 : : */
34 : : const uint8 pg_leftmost_one_pos[256] = {
35 : : 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
36 : : 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
37 : : 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
38 : : 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
39 : : 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
40 : : 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
41 : : 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
42 : : 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
43 : : 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
44 : : 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
45 : : 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
46 : : 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
47 : : 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
48 : : 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
49 : : 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
50 : : 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
51 : : };
52 : :
53 : : /*
54 : : * Array giving the position of the right-most set bit for each possible
55 : : * byte value. We count the right-most position as the 0th bit, and the
56 : : * left-most the 7th bit. The 0th entry of the array should not be used.
57 : : *
58 : : * Note: this is not used by the functions in pg_bitutils.h when
59 : : * HAVE__BUILTIN_CTZ is defined, but we provide it anyway, so that
60 : : * extensions possibly compiled with a different compiler can use it.
61 : : */
62 : : const uint8 pg_rightmost_one_pos[256] = {
63 : : 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
64 : : 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
65 : : 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
66 : : 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
67 : : 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
68 : : 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
69 : : 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
70 : : 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
71 : : 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
72 : : 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
73 : : 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
74 : : 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
75 : : 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
76 : : 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
77 : : 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
78 : : 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
79 : : };
80 : :
81 : : /*
82 : : * Array giving the number of 1-bits in each possible byte value.
83 : : *
84 : : * Note: we export this for use by functions in which explicit use
85 : : * of the popcount functions seems unlikely to be a win.
86 : : */
87 : : const uint8 pg_number_of_ones[256] = {
88 : : 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
89 : : 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
90 : : 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
91 : : 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
92 : : 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
93 : : 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
94 : : 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
95 : : 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
96 : : 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
97 : : 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
98 : : 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
99 : : 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
100 : : 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
101 : : 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
102 : : 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
103 : : 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
104 : : };
105 : :
106 : : static inline int pg_popcount32_slow(uint32 word);
107 : : static inline int pg_popcount64_slow(uint64 word);
108 : : static uint64 pg_popcount_slow(const char *buf, int bytes);
109 : : static uint64 pg_popcount_masked_slow(const char *buf, int bytes, bits8 mask);
110 : :
111 : : #ifdef TRY_POPCNT_FAST
112 : : static bool pg_popcount_available(void);
113 : : static int pg_popcount32_choose(uint32 word);
114 : : static int pg_popcount64_choose(uint64 word);
115 : : static uint64 pg_popcount_choose(const char *buf, int bytes);
116 : : static uint64 pg_popcount_masked_choose(const char *buf, int bytes, bits8 mask);
117 : : static inline int pg_popcount32_fast(uint32 word);
118 : : static inline int pg_popcount64_fast(uint64 word);
119 : : static uint64 pg_popcount_fast(const char *buf, int bytes);
120 : : static uint64 pg_popcount_masked_fast(const char *buf, int bytes, bits8 mask);
121 : :
122 : : int (*pg_popcount32) (uint32 word) = pg_popcount32_choose;
123 : : int (*pg_popcount64) (uint64 word) = pg_popcount64_choose;
124 : : uint64 (*pg_popcount_optimized) (const char *buf, int bytes) = pg_popcount_choose;
125 : : uint64 (*pg_popcount_masked_optimized) (const char *buf, int bytes, bits8 mask) = pg_popcount_masked_choose;
126 : : #endif /* TRY_POPCNT_FAST */
127 : :
128 : : #ifdef TRY_POPCNT_FAST
129 : :
130 : : /*
131 : : * Return true if CPUID indicates that the POPCNT instruction is available.
132 : : */
133 : : static bool
1885 tgl@sss.pgh.pa.us 134 :CBC 7885 : pg_popcount_available(void)
135 : : {
136 : 7885 : unsigned int exx[4] = {0, 0, 0, 0};
137 : :
138 : : #if defined(HAVE__GET_CPUID)
139 : 7885 : __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
140 : : #elif defined(HAVE__CPUID)
141 : : __cpuid(exx, 1);
142 : : #else
143 : : #error cpuid instruction not available
144 : : #endif
145 : :
146 : 7885 : return (exx[2] & (1 << 23)) != 0; /* POPCNT */
147 : : }
148 : :
149 : : /*
150 : : * These functions get called on the first call to pg_popcount32 etc.
151 : : * They detect whether we can use the asm implementations, and replace
152 : : * the function pointers so that subsequent calls are routed directly to
153 : : * the chosen implementation.
154 : : */
155 : : static inline void
12 nathan@postgresql.or 156 :GNC 7885 : choose_popcount_functions(void)
157 : : {
1885 tgl@sss.pgh.pa.us 158 [ + - ]:CBC 7885 : if (pg_popcount_available())
159 : : {
979 drowley@postgresql.o 160 : 7885 : pg_popcount32 = pg_popcount32_fast;
161 : 7885 : pg_popcount64 = pg_popcount64_fast;
11 nathan@postgresql.or 162 :GNC 7885 : pg_popcount_optimized = pg_popcount_fast;
8 163 : 7885 : pg_popcount_masked_optimized = pg_popcount_masked_fast;
164 : : }
165 : : else
166 : : {
1885 tgl@sss.pgh.pa.us 167 :UBC 0 : pg_popcount32 = pg_popcount32_slow;
168 : 0 : pg_popcount64 = pg_popcount64_slow;
11 nathan@postgresql.or 169 :UNC 0 : pg_popcount_optimized = pg_popcount_slow;
8 170 : 0 : pg_popcount_masked_optimized = pg_popcount_masked_slow;
171 : : }
172 : :
173 : : #ifdef USE_AVX512_POPCNT_WITH_RUNTIME_CHECK
8 nathan@postgresql.or 174 [ - + ]:GNC 7885 : if (pg_popcount_avx512_available())
175 : : {
8 nathan@postgresql.or 176 :UNC 0 : pg_popcount_optimized = pg_popcount_avx512;
177 : 0 : pg_popcount_masked_optimized = pg_popcount_masked_avx512;
178 : : }
179 : : #endif
12 nathan@postgresql.or 180 :GNC 7885 : }
181 : :
182 : : static int
183 : 3 : pg_popcount32_choose(uint32 word)
184 : : {
185 : 3 : choose_popcount_functions();
1885 tgl@sss.pgh.pa.us 186 :CBC 3 : return pg_popcount32(word);
187 : : }
188 : :
189 : : static int
190 : 7142 : pg_popcount64_choose(uint64 word)
191 : : {
12 nathan@postgresql.or 192 :GNC 7142 : choose_popcount_functions();
1885 tgl@sss.pgh.pa.us 193 :CBC 7142 : return pg_popcount64(word);
194 : : }
195 : :
196 : : static uint64
26 nathan@postgresql.or 197 :GNC 2 : pg_popcount_choose(const char *buf, int bytes)
198 : : {
12 199 : 2 : choose_popcount_functions();
11 200 : 2 : return pg_popcount_optimized(buf, bytes);
201 : : }
202 : :
203 : : static uint64
8 204 : 738 : pg_popcount_masked_choose(const char *buf, int bytes, bits8 mask)
205 : : {
206 : 738 : choose_popcount_functions();
207 : 738 : return pg_popcount_masked(buf, bytes, mask);
208 : : }
209 : :
210 : : /*
211 : : * pg_popcount32_fast
212 : : * Return the number of 1 bits set in word
213 : : */
214 : : static inline int
979 drowley@postgresql.o 215 :CBC 81 : pg_popcount32_fast(uint32 word)
216 : : {
217 : : #ifdef _MSC_VER
218 : : return __popcnt(word);
219 : : #else
220 : : uint32 res;
221 : :
1789 tgl@sss.pgh.pa.us 222 : 81 : __asm__ __volatile__(" popcntl %1,%0\n":"=q"(res):"rm"(word):"cc");
1885 223 : 81 : return (int) res;
224 : : #endif
225 : : }
226 : :
227 : : /*
228 : : * pg_popcount64_fast
229 : : * Return the number of 1 bits set in word
230 : : */
231 : : static inline int
979 drowley@postgresql.o 232 : 37614927 : pg_popcount64_fast(uint64 word)
233 : : {
234 : : #ifdef _MSC_VER
235 : : return __popcnt64(word);
236 : : #else
237 : : uint64 res;
238 : :
1789 tgl@sss.pgh.pa.us 239 : 37614927 : __asm__ __volatile__(" popcntq %1,%0\n":"=q"(res):"rm"(word):"cc");
1885 240 : 37614927 : return (int) res;
241 : : #endif
242 : : }
243 : :
244 : : /*
245 : : * pg_popcount_fast
246 : : * Returns the number of 1-bits in buf
247 : : */
248 : : static uint64
26 nathan@postgresql.or 249 :GNC 21 : pg_popcount_fast(const char *buf, int bytes)
250 : : {
251 : 21 : uint64 popcnt = 0;
252 : :
253 : : #if SIZEOF_VOID_P >= 8
254 : : /* Process in 64-bit chunks if the buffer is aligned. */
255 [ + - ]: 21 : if (buf == (const char *) TYPEALIGN(8, buf))
256 : : {
257 : 21 : const uint64 *words = (const uint64 *) buf;
258 : :
259 [ + + ]: 262471 : while (bytes >= 8)
260 : : {
261 : 262450 : popcnt += pg_popcount64_fast(*words++);
262 : 262450 : bytes -= 8;
263 : : }
264 : :
265 : 21 : buf = (const char *) words;
266 : : }
267 : : #else
268 : : /* Process in 32-bit chunks if the buffer is aligned. */
269 : : if (buf == (const char *) TYPEALIGN(4, buf))
270 : : {
271 : : const uint32 *words = (const uint32 *) buf;
272 : :
273 : : while (bytes >= 4)
274 : : {
275 : : popcnt += pg_popcount32_fast(*words++);
276 : : bytes -= 4;
277 : : }
278 : :
279 : : buf = (const char *) words;
280 : : }
281 : : #endif
282 : :
283 : : /* Process any remaining bytes */
284 [ + + ]: 109 : while (bytes--)
285 : 88 : popcnt += pg_number_of_ones[(unsigned char) *buf++];
286 : :
287 : 21 : return popcnt;
288 : : }
289 : :
290 : : /*
291 : : * pg_popcount_masked_fast
292 : : * Returns the number of 1-bits in buf after applying the mask to each byte
293 : : */
294 : : static uint64
8 295 : 35484 : pg_popcount_masked_fast(const char *buf, int bytes, bits8 mask)
296 : : {
297 : 35484 : uint64 popcnt = 0;
298 : :
299 : : #if SIZEOF_VOID_P >= 8
300 : : /* Process in 64-bit chunks if the buffer is aligned */
301 : 35484 : uint64 maskv = ~UINT64CONST(0) / 0xFF * mask;
302 : :
303 [ + - ]: 35484 : if (buf == (const char *) TYPEALIGN(8, buf))
304 : : {
305 : 35484 : const uint64 *words = (const uint64 *) buf;
306 : :
307 [ + + ]: 36264648 : while (bytes >= 8)
308 : : {
309 : 36229164 : popcnt += pg_popcount64_fast(*words++ & maskv);
310 : 36229164 : bytes -= 8;
311 : : }
312 : :
313 : 35484 : buf = (const char *) words;
314 : : }
315 : : #else
316 : : /* Process in 32-bit chunks if the buffer is aligned. */
317 : : uint32 maskv = ~((uint32) 0) / 0xFF * mask;
318 : :
319 : : if (buf == (const char *) TYPEALIGN(4, buf))
320 : : {
321 : : const uint32 *words = (const uint32 *) buf;
322 : :
323 : : while (bytes >= 4)
324 : : {
325 : : popcnt += pg_popcount32_fast(*words++ & maskv);
326 : : bytes -= 4;
327 : : }
328 : :
329 : : buf = (const char *) words;
330 : : }
331 : : #endif
332 : :
333 : : /* Process any remaining bytes */
334 [ - + ]: 35484 : while (bytes--)
8 nathan@postgresql.or 335 :UNC 0 : popcnt += pg_number_of_ones[(unsigned char) *buf++ & mask];
336 : :
8 nathan@postgresql.or 337 :GNC 35484 : return popcnt;
338 : : }
339 : :
340 : : #endif /* TRY_POPCNT_FAST */
341 : :
342 : :
343 : : /*
344 : : * pg_popcount32_slow
345 : : * Return the number of 1 bits set in word
346 : : */
347 : : static inline int
1885 tgl@sss.pgh.pa.us 348 :UBC 0 : pg_popcount32_slow(uint32 word)
349 : : {
350 : : #ifdef HAVE__BUILTIN_POPCOUNT
351 : 0 : return __builtin_popcount(word);
352 : : #else /* !HAVE__BUILTIN_POPCOUNT */
353 : : int result = 0;
354 : :
355 : : while (word != 0)
356 : : {
357 : : result += pg_number_of_ones[word & 255];
358 : : word >>= 8;
359 : : }
360 : :
361 : : return result;
362 : : #endif /* HAVE__BUILTIN_POPCOUNT */
363 : : }
364 : :
365 : : /*
366 : : * pg_popcount64_slow
367 : : * Return the number of 1 bits set in word
368 : : */
369 : : static inline int
370 : 0 : pg_popcount64_slow(uint64 word)
371 : : {
372 : : #ifdef HAVE__BUILTIN_POPCOUNT
373 : : #if defined(HAVE_LONG_INT_64)
374 : 0 : return __builtin_popcountl(word);
375 : : #elif defined(HAVE_LONG_LONG_INT_64)
376 : : return __builtin_popcountll(word);
377 : : #else
378 : : #error must have a working 64-bit integer datatype
379 : : #endif
380 : : #else /* !HAVE__BUILTIN_POPCOUNT */
381 : : int result = 0;
382 : :
383 : : while (word != 0)
384 : : {
385 : : result += pg_number_of_ones[word & 255];
386 : : word >>= 8;
387 : : }
388 : :
389 : : return result;
390 : : #endif /* HAVE__BUILTIN_POPCOUNT */
391 : : }
392 : :
393 : : /*
394 : : * pg_popcount_slow
395 : : * Returns the number of 1-bits in buf
396 : : */
397 : : static uint64
26 nathan@postgresql.or 398 :UNC 0 : pg_popcount_slow(const char *buf, int bytes)
399 : : {
1885 tgl@sss.pgh.pa.us 400 : 0 : uint64 popcnt = 0;
401 : :
402 : : #if SIZEOF_VOID_P >= 8
403 : : /* Process in 64-bit chunks if the buffer is aligned. */
404 [ # # ]: 0 : if (buf == (const char *) TYPEALIGN(8, buf))
405 : : {
406 : 0 : const uint64 *words = (const uint64 *) buf;
407 : :
408 [ # # ]: 0 : while (bytes >= 8)
409 : : {
26 nathan@postgresql.or 410 : 0 : popcnt += pg_popcount64_slow(*words++);
1885 tgl@sss.pgh.pa.us 411 : 0 : bytes -= 8;
412 : : }
413 : :
414 : 0 : buf = (const char *) words;
415 : : }
416 : : #else
417 : : /* Process in 32-bit chunks if the buffer is aligned. */
418 : : if (buf == (const char *) TYPEALIGN(4, buf))
419 : : {
420 : : const uint32 *words = (const uint32 *) buf;
421 : :
422 : : while (bytes >= 4)
423 : : {
424 : : popcnt += pg_popcount32_slow(*words++);
425 : : bytes -= 4;
426 : : }
427 : :
428 : : buf = (const char *) words;
429 : : }
430 : : #endif
431 : :
432 : : /* Process any remaining bytes */
433 [ # # ]: 0 : while (bytes--)
434 : 0 : popcnt += pg_number_of_ones[(unsigned char) *buf++];
435 : :
436 : 0 : return popcnt;
437 : : }
438 : :
439 : : /*
440 : : * pg_popcount_masked_slow
441 : : * Returns the number of 1-bits in buf after applying the mask to each byte
442 : : */
443 : : static uint64
8 nathan@postgresql.or 444 : 0 : pg_popcount_masked_slow(const char *buf, int bytes, bits8 mask)
445 : : {
446 : 0 : uint64 popcnt = 0;
447 : :
448 : : #if SIZEOF_VOID_P >= 8
449 : : /* Process in 64-bit chunks if the buffer is aligned */
450 : 0 : uint64 maskv = ~UINT64CONST(0) / 0xFF * mask;
451 : :
452 [ # # ]: 0 : if (buf == (const char *) TYPEALIGN(8, buf))
453 : : {
454 : 0 : const uint64 *words = (const uint64 *) buf;
455 : :
456 [ # # ]: 0 : while (bytes >= 8)
457 : : {
458 : 0 : popcnt += pg_popcount64_slow(*words++ & maskv);
459 : 0 : bytes -= 8;
460 : : }
461 : :
462 : 0 : buf = (const char *) words;
463 : : }
464 : : #else
465 : : /* Process in 32-bit chunks if the buffer is aligned. */
466 : : uint32 maskv = ~((uint32) 0) / 0xFF * mask;
467 : :
468 : : if (buf == (const char *) TYPEALIGN(4, buf))
469 : : {
470 : : const uint32 *words = (const uint32 *) buf;
471 : :
472 : : while (bytes >= 4)
473 : : {
474 : : popcnt += pg_popcount32_slow(*words++ & maskv);
475 : : bytes -= 4;
476 : : }
477 : :
478 : : buf = (const char *) words;
479 : : }
480 : : #endif
481 : :
482 : : /* Process any remaining bytes */
483 [ # # ]: 0 : while (bytes--)
484 : 0 : popcnt += pg_number_of_ones[(unsigned char) *buf++ & mask];
485 : :
486 : 0 : return popcnt;
487 : : }
488 : :
489 : : #ifndef TRY_POPCNT_FAST
490 : :
491 : : /*
492 : : * When the POPCNT instruction is not available, there's no point in using
493 : : * function pointers to vary the implementation between the fast and slow
494 : : * method. We instead just make these actual external functions when
495 : : * TRY_POPCNT_FAST is not defined. The compiler should be able to inline
496 : : * the slow versions here.
497 : : */
498 : : int
499 : : pg_popcount32(uint32 word)
500 : : {
501 : : return pg_popcount32_slow(word);
502 : : }
503 : :
504 : : int
505 : : pg_popcount64(uint64 word)
506 : : {
507 : : return pg_popcount64_slow(word);
508 : : }
509 : :
510 : : /*
511 : : * pg_popcount_optimized
512 : : * Returns the number of 1-bits in buf
513 : : */
514 : : uint64
515 : : pg_popcount_optimized(const char *buf, int bytes)
516 : : {
517 : : return pg_popcount_slow(buf, bytes);
518 : : }
519 : :
520 : : /*
521 : : * pg_popcount_masked_optimized
522 : : * Returns the number of 1-bits in buf after applying the mask to each byte
523 : : */
524 : : uint64
525 : : pg_popcount_masked_optimized(const char *buf, int bytes, bits8 mask)
526 : : {
527 : : return pg_popcount_masked_slow(buf, bytes, mask);
528 : : }
529 : :
530 : : #endif /* !TRY_POPCNT_FAST */
|