LCOV - differential code coverage report
Current view: top level - src/port - pg_bitutils.c (source / functions) Coverage Total Hit UNC UBC GNC CBC DUB DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 60.5 % 86 52 28 6 36 16 2 15
Current Date: 2024-04-14 14:21:10 Functions: 71.4 % 14 10 2 2 7 3 2
Baseline: 16@8cea358b128 Branches: 39.3 % 28 11 16 1 10 1
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 65.5 % 55 36 19 36
(240..) days: 51.6 % 31 16 9 6 16
Function coverage date bins:
[..60] days: 75.0 % 8 6 2 6
(240..) days: 66.7 % 6 4 2 1 3
Branch coverage date bins:
[..60] days: 50.0 % 20 10 10 10
(240..) days: 12.5 % 8 1 6 1 1

 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 */
        

Generated by: LCOV version 2.1-beta2-3-g6141622