LCOV - code coverage report
Current view: top level - src/port - pg_popcount_aarch64.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 51.3 % 199 102
Test Date: 2026-01-26 10:56:24 Functions: 80.0 % 10 8
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 50.0 % 30 15

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * pg_popcount_aarch64.c
       4                 :             :  *        Holds the AArch64 popcount implementations.
       5                 :             :  *
       6                 :             :  * Copyright (c) 2025-2026, PostgreSQL Global Development Group
       7                 :             :  *
       8                 :             :  * IDENTIFICATION
       9                 :             :  *        src/port/pg_popcount_aarch64.c
      10                 :             :  *
      11                 :             :  *-------------------------------------------------------------------------
      12                 :             :  */
      13                 :             : #include "c.h"
      14                 :             : 
      15                 :             : #ifdef USE_NEON
      16                 :             : 
      17                 :             : #include <arm_neon.h>
      18                 :             : 
      19                 :             : #ifdef USE_SVE_POPCNT_WITH_RUNTIME_CHECK
      20                 :             : #include <arm_sve.h>
      21                 :             : 
      22                 :             : #if defined(HAVE_ELF_AUX_INFO) || defined(HAVE_GETAUXVAL)
      23                 :             : #include <sys/auxv.h>
      24                 :             : /* Ancient glibc releases don't include the HWCAPxxx macros in sys/auxv.h */
      25                 :             : #if defined(__linux__) && !defined(HWCAP_SVE)
      26                 :             : #include <asm/hwcap.h>
      27                 :             : #endif
      28                 :             : #endif
      29                 :             : #endif
      30                 :             : 
      31                 :             : #include "port/pg_bitutils.h"
      32                 :             : 
      33                 :             : /*
      34                 :             :  * The Neon versions are built regardless of whether we are building the SVE
      35                 :             :  * versions.
      36                 :             :  */
      37                 :             : static uint64 pg_popcount_neon(const char *buf, int bytes);
      38                 :             : static uint64 pg_popcount_masked_neon(const char *buf, int bytes, bits8 mask);
      39                 :             : 
      40                 :             : #ifdef USE_SVE_POPCNT_WITH_RUNTIME_CHECK
      41                 :             : 
      42                 :             : /*
      43                 :             :  * These are the SVE implementations of the popcount functions.
      44                 :             :  */
      45                 :             : static uint64 pg_popcount_sve(const char *buf, int bytes);
      46                 :             : static uint64 pg_popcount_masked_sve(const char *buf, int bytes, bits8 mask);
      47                 :             : 
      48                 :             : /*
      49                 :             :  * The function pointers are initially set to "choose" functions.  These
      50                 :             :  * functions will first set the pointers to the right implementations (based on
      51                 :             :  * what the current CPU supports) and then will call the pointer to fulfill the
      52                 :             :  * caller's request.
      53                 :             :  */
      54                 :             : static uint64 pg_popcount_choose(const char *buf, int bytes);
      55                 :             : static uint64 pg_popcount_masked_choose(const char *buf, int bytes, bits8 mask);
      56                 :             : uint64          (*pg_popcount_optimized) (const char *buf, int bytes) = pg_popcount_choose;
      57                 :             : uint64          (*pg_popcount_masked_optimized) (const char *buf, int bytes, bits8 mask) = pg_popcount_masked_choose;
      58                 :             : 
      59                 :             : static inline bool
      60                 :          38 : pg_popcount_sve_available(void)
      61                 :             : {
      62                 :             : #ifdef HAVE_ELF_AUX_INFO
      63                 :             :         unsigned long value;
      64                 :             : 
      65                 :             :         return elf_aux_info(AT_HWCAP, &value, sizeof(value)) == 0 &&
      66                 :             :                 (value & HWCAP_SVE) != 0;
      67                 :             : #elif defined(HAVE_GETAUXVAL)
      68                 :             :         return (getauxval(AT_HWCAP) & HWCAP_SVE) != 0;
      69                 :             : #else
      70                 :          38 :         return false;
      71                 :             : #endif
      72                 :             : }
      73                 :             : 
      74                 :             : static inline void
      75                 :          38 : choose_popcount_functions(void)
      76                 :             : {
      77         [ -  + ]:          38 :         if (pg_popcount_sve_available())
      78                 :             :         {
      79                 :           0 :                 pg_popcount_optimized = pg_popcount_sve;
      80                 :           0 :                 pg_popcount_masked_optimized = pg_popcount_masked_sve;
      81                 :           0 :         }
      82                 :             :         else
      83                 :             :         {
      84                 :          38 :                 pg_popcount_optimized = pg_popcount_neon;
      85                 :          38 :                 pg_popcount_masked_optimized = pg_popcount_masked_neon;
      86                 :             :         }
      87                 :          38 : }
      88                 :             : 
      89                 :             : static uint64
      90                 :           1 : pg_popcount_choose(const char *buf, int bytes)
      91                 :             : {
      92                 :           1 :         choose_popcount_functions();
      93                 :           1 :         return pg_popcount_optimized(buf, bytes);
      94                 :             : }
      95                 :             : 
      96                 :             : static uint64
      97                 :          37 : pg_popcount_masked_choose(const char *buf, int bytes, bits8 mask)
      98                 :             : {
      99                 :          37 :         choose_popcount_functions();
     100                 :          37 :         return pg_popcount_masked_optimized(buf, bytes, mask);
     101                 :             : }
     102                 :             : 
     103                 :             : /*
     104                 :             :  * pg_popcount_sve
     105                 :             :  *              Returns number of 1 bits in buf
     106                 :             :  */
     107                 :             : pg_attribute_target("arch=armv8-a+sve")
     108                 :             : static uint64
     109                 :           0 : pg_popcount_sve(const char *buf, int bytes)
     110                 :             : {
     111                 :           0 :         svbool_t        pred = svptrue_b64();
     112                 :           0 :         svuint64_t      accum1 = svdup_u64(0),
     113                 :           0 :                                 accum2 = svdup_u64(0),
     114                 :           0 :                                 accum3 = svdup_u64(0),
     115                 :           0 :                                 accum4 = svdup_u64(0);
     116                 :           0 :         uint32          vec_len = svcntb(),
     117                 :           0 :                                 bytes_per_iteration = 4 * vec_len;
     118                 :           0 :         uint64          popcnt = 0;
     119                 :             : 
     120                 :             :         /*
     121                 :             :          * For better instruction-level parallelism, each loop iteration operates
     122                 :             :          * on a block of four registers.
     123                 :             :          */
     124         [ #  # ]:           0 :         for (; bytes >= bytes_per_iteration; bytes -= bytes_per_iteration)
     125                 :             :         {
     126                 :           0 :                 svuint64_t      vec;
     127                 :             : 
     128                 :           0 :                 vec = svld1_u64(pred, (const uint64 *) buf);
     129                 :           0 :                 accum1 = svadd_u64_x(pred, accum1, svcnt_u64_x(pred, vec));
     130                 :           0 :                 buf += vec_len;
     131                 :             : 
     132                 :           0 :                 vec = svld1_u64(pred, (const uint64 *) buf);
     133                 :           0 :                 accum2 = svadd_u64_x(pred, accum2, svcnt_u64_x(pred, vec));
     134                 :           0 :                 buf += vec_len;
     135                 :             : 
     136                 :           0 :                 vec = svld1_u64(pred, (const uint64 *) buf);
     137                 :           0 :                 accum3 = svadd_u64_x(pred, accum3, svcnt_u64_x(pred, vec));
     138                 :           0 :                 buf += vec_len;
     139                 :             : 
     140                 :           0 :                 vec = svld1_u64(pred, (const uint64 *) buf);
     141                 :           0 :                 accum4 = svadd_u64_x(pred, accum4, svcnt_u64_x(pred, vec));
     142                 :           0 :                 buf += vec_len;
     143                 :           0 :         }
     144                 :             : 
     145                 :             :         /*
     146                 :             :          * If enough data remains, do another iteration on a block of two
     147                 :             :          * registers.
     148                 :             :          */
     149                 :           0 :         bytes_per_iteration = 2 * vec_len;
     150         [ #  # ]:           0 :         if (bytes >= bytes_per_iteration)
     151                 :             :         {
     152                 :           0 :                 svuint64_t      vec;
     153                 :             : 
     154                 :           0 :                 vec = svld1_u64(pred, (const uint64 *) buf);
     155                 :           0 :                 accum1 = svadd_u64_x(pred, accum1, svcnt_u64_x(pred, vec));
     156                 :           0 :                 buf += vec_len;
     157                 :             : 
     158                 :           0 :                 vec = svld1_u64(pred, (const uint64 *) buf);
     159                 :           0 :                 accum2 = svadd_u64_x(pred, accum2, svcnt_u64_x(pred, vec));
     160                 :           0 :                 buf += vec_len;
     161                 :             : 
     162                 :           0 :                 bytes -= bytes_per_iteration;
     163                 :           0 :         }
     164                 :             : 
     165                 :             :         /*
     166                 :             :          * Add the accumulators.
     167                 :             :          */
     168                 :           0 :         popcnt += svaddv_u64(pred, svadd_u64_x(pred, accum1, accum2));
     169                 :           0 :         popcnt += svaddv_u64(pred, svadd_u64_x(pred, accum3, accum4));
     170                 :             : 
     171                 :             :         /*
     172                 :             :          * Process any remaining data.
     173                 :             :          */
     174         [ #  # ]:           0 :         for (; bytes > 0; bytes -= vec_len)
     175                 :             :         {
     176                 :           0 :                 svuint8_t       vec;
     177                 :             : 
     178                 :           0 :                 pred = svwhilelt_b8_s32(0, bytes);
     179                 :           0 :                 vec = svld1_u8(pred, (const uint8 *) buf);
     180                 :           0 :                 popcnt += svaddv_u8(pred, svcnt_u8_x(pred, vec));
     181                 :           0 :                 buf += vec_len;
     182                 :           0 :         }
     183                 :             : 
     184                 :           0 :         return popcnt;
     185                 :           0 : }
     186                 :             : 
     187                 :             : /*
     188                 :             :  * pg_popcount_masked_sve
     189                 :             :  *              Returns number of 1 bits in buf after applying the mask to each byte
     190                 :             :  */
     191                 :             : pg_attribute_target("arch=armv8-a+sve")
     192                 :             : static uint64
     193                 :           0 : pg_popcount_masked_sve(const char *buf, int bytes, bits8 mask)
     194                 :             : {
     195                 :           0 :         svbool_t        pred = svptrue_b64();
     196                 :           0 :         svuint64_t      accum1 = svdup_u64(0),
     197                 :           0 :                                 accum2 = svdup_u64(0),
     198                 :           0 :                                 accum3 = svdup_u64(0),
     199                 :           0 :                                 accum4 = svdup_u64(0);
     200                 :           0 :         uint32          vec_len = svcntb(),
     201                 :           0 :                                 bytes_per_iteration = 4 * vec_len;
     202                 :           0 :         uint64          popcnt = 0,
     203                 :           0 :                                 mask64 = ~UINT64CONST(0) / 0xFF * mask;
     204                 :             : 
     205                 :             :         /*
     206                 :             :          * For better instruction-level parallelism, each loop iteration operates
     207                 :             :          * on a block of four registers.
     208                 :             :          */
     209         [ #  # ]:           0 :         for (; bytes >= bytes_per_iteration; bytes -= bytes_per_iteration)
     210                 :             :         {
     211                 :           0 :                 svuint64_t      vec;
     212                 :             : 
     213                 :           0 :                 vec = svand_n_u64_x(pred, svld1_u64(pred, (const uint64 *) buf), mask64);
     214                 :           0 :                 accum1 = svadd_u64_x(pred, accum1, svcnt_u64_x(pred, vec));
     215                 :           0 :                 buf += vec_len;
     216                 :             : 
     217                 :           0 :                 vec = svand_n_u64_x(pred, svld1_u64(pred, (const uint64 *) buf), mask64);
     218                 :           0 :                 accum2 = svadd_u64_x(pred, accum2, svcnt_u64_x(pred, vec));
     219                 :           0 :                 buf += vec_len;
     220                 :             : 
     221                 :           0 :                 vec = svand_n_u64_x(pred, svld1_u64(pred, (const uint64 *) buf), mask64);
     222                 :           0 :                 accum3 = svadd_u64_x(pred, accum3, svcnt_u64_x(pred, vec));
     223                 :           0 :                 buf += vec_len;
     224                 :             : 
     225                 :           0 :                 vec = svand_n_u64_x(pred, svld1_u64(pred, (const uint64 *) buf), mask64);
     226                 :           0 :                 accum4 = svadd_u64_x(pred, accum4, svcnt_u64_x(pred, vec));
     227                 :           0 :                 buf += vec_len;
     228                 :           0 :         }
     229                 :             : 
     230                 :             :         /*
     231                 :             :          * If enough data remains, do another iteration on a block of two
     232                 :             :          * registers.
     233                 :             :          */
     234                 :           0 :         bytes_per_iteration = 2 * vec_len;
     235         [ #  # ]:           0 :         if (bytes >= bytes_per_iteration)
     236                 :             :         {
     237                 :           0 :                 svuint64_t      vec;
     238                 :             : 
     239                 :           0 :                 vec = svand_n_u64_x(pred, svld1_u64(pred, (const uint64 *) buf), mask64);
     240                 :           0 :                 accum1 = svadd_u64_x(pred, accum1, svcnt_u64_x(pred, vec));
     241                 :           0 :                 buf += vec_len;
     242                 :             : 
     243                 :           0 :                 vec = svand_n_u64_x(pred, svld1_u64(pred, (const uint64 *) buf), mask64);
     244                 :           0 :                 accum2 = svadd_u64_x(pred, accum2, svcnt_u64_x(pred, vec));
     245                 :           0 :                 buf += vec_len;
     246                 :             : 
     247                 :           0 :                 bytes -= bytes_per_iteration;
     248                 :           0 :         }
     249                 :             : 
     250                 :             :         /*
     251                 :             :          * Add the accumulators.
     252                 :             :          */
     253                 :           0 :         popcnt += svaddv_u64(pred, svadd_u64_x(pred, accum1, accum2));
     254                 :           0 :         popcnt += svaddv_u64(pred, svadd_u64_x(pred, accum3, accum4));
     255                 :             : 
     256                 :             :         /*
     257                 :             :          * Process any remaining data.
     258                 :             :          */
     259         [ #  # ]:           0 :         for (; bytes > 0; bytes -= vec_len)
     260                 :             :         {
     261                 :           0 :                 svuint8_t       vec;
     262                 :             : 
     263                 :           0 :                 pred = svwhilelt_b8_s32(0, bytes);
     264                 :           0 :                 vec = svand_n_u8_x(pred, svld1_u8(pred, (const uint8 *) buf), mask);
     265                 :           0 :                 popcnt += svaddv_u8(pred, svcnt_u8_x(pred, vec));
     266                 :           0 :                 buf += vec_len;
     267                 :           0 :         }
     268                 :             : 
     269                 :           0 :         return popcnt;
     270                 :           0 : }
     271                 :             : 
     272                 :             : #else                                                   /* USE_SVE_POPCNT_WITH_RUNTIME_CHECK */
     273                 :             : 
     274                 :             : /*
     275                 :             :  * When the SVE version isn't available, there's no point in using function
     276                 :             :  * pointers to vary the implementation.  We instead just make these actual
     277                 :             :  * external functions when USE_SVE_POPCNT_WITH_RUNTIME_CHECK is not defined.
     278                 :             :  * The compiler should be able to inline the Neon versions here.
     279                 :             :  */
     280                 :             : uint64
     281                 :             : pg_popcount_optimized(const char *buf, int bytes)
     282                 :             : {
     283                 :             :         return pg_popcount_neon(buf, bytes);
     284                 :             : }
     285                 :             : 
     286                 :             : uint64
     287                 :             : pg_popcount_masked_optimized(const char *buf, int bytes, bits8 mask)
     288                 :             : {
     289                 :             :         return pg_popcount_masked_neon(buf, bytes, mask);
     290                 :             : }
     291                 :             : 
     292                 :             : #endif                                                  /* ! USE_SVE_POPCNT_WITH_RUNTIME_CHECK */
     293                 :             : 
     294                 :             : /*
     295                 :             :  * pg_popcount32
     296                 :             :  *              Return number of 1 bits in word
     297                 :             :  */
     298                 :             : int
     299                 :          26 : pg_popcount32(uint32 word)
     300                 :             : {
     301                 :          26 :         return pg_popcount64((uint64) word);
     302                 :             : }
     303                 :             : 
     304                 :             : /*
     305                 :             :  * pg_popcount64
     306                 :             :  *              Return number of 1 bits in word
     307                 :             :  */
     308                 :             : int
     309                 :      706107 : pg_popcount64(uint64 word)
     310                 :             : {
     311                 :             :         /*
     312                 :             :          * For some compilers, __builtin_popcountl() already emits Neon
     313                 :             :          * instructions.  The line below should compile to the same code on those
     314                 :             :          * systems.
     315                 :             :          */
     316                 :      706107 :         return vaddv_u8(vcnt_u8(vld1_u8((const uint8 *) &word)));
     317                 :             : }
     318                 :             : 
     319                 :             : /*
     320                 :             :  * pg_popcount_neon
     321                 :             :  *              Returns number of 1 bits in buf
     322                 :             :  */
     323                 :             : static uint64
     324                 :           4 : pg_popcount_neon(const char *buf, int bytes)
     325                 :             : {
     326                 :           4 :         uint8x16_t      vec;
     327                 :          12 :         uint64x2_t      accum1 = vdupq_n_u64(0),
     328                 :           4 :                                 accum2 = vdupq_n_u64(0),
     329                 :           4 :                                 accum3 = vdupq_n_u64(0),
     330                 :           4 :                                 accum4 = vdupq_n_u64(0);
     331                 :           4 :         uint32          bytes_per_iteration = 4 * sizeof(uint8x16_t);
     332                 :           4 :         uint64          popcnt = 0;
     333                 :             : 
     334                 :             :         /*
     335                 :             :          * For better instruction-level parallelism, each loop iteration operates
     336                 :             :          * on a block of four registers.
     337                 :             :          */
     338         [ +  + ]:           6 :         for (; bytes >= bytes_per_iteration; bytes -= bytes_per_iteration)
     339                 :             :         {
     340                 :           2 :                 vec = vld1q_u8((const uint8 *) buf);
     341                 :           2 :                 accum1 = vpadalq_u32(accum1, vpaddlq_u16(vpaddlq_u8(vcntq_u8(vec))));
     342                 :           2 :                 buf += sizeof(uint8x16_t);
     343                 :             : 
     344                 :           2 :                 vec = vld1q_u8((const uint8 *) buf);
     345                 :           2 :                 accum2 = vpadalq_u32(accum2, vpaddlq_u16(vpaddlq_u8(vcntq_u8(vec))));
     346                 :           2 :                 buf += sizeof(uint8x16_t);
     347                 :             : 
     348                 :           2 :                 vec = vld1q_u8((const uint8 *) buf);
     349                 :           2 :                 accum3 = vpadalq_u32(accum3, vpaddlq_u16(vpaddlq_u8(vcntq_u8(vec))));
     350                 :           2 :                 buf += sizeof(uint8x16_t);
     351                 :             : 
     352                 :           2 :                 vec = vld1q_u8((const uint8 *) buf);
     353                 :           2 :                 accum4 = vpadalq_u32(accum4, vpaddlq_u16(vpaddlq_u8(vcntq_u8(vec))));
     354                 :           2 :                 buf += sizeof(uint8x16_t);
     355                 :           2 :         }
     356                 :             : 
     357                 :             :         /*
     358                 :             :          * If enough data remains, do another iteration on a block of two
     359                 :             :          * registers.
     360                 :             :          */
     361                 :           4 :         bytes_per_iteration = 2 * sizeof(uint8x16_t);
     362         [ +  + ]:           4 :         if (bytes >= bytes_per_iteration)
     363                 :             :         {
     364                 :           2 :                 vec = vld1q_u8((const uint8 *) buf);
     365                 :           2 :                 accum1 = vpadalq_u32(accum1, vpaddlq_u16(vpaddlq_u8(vcntq_u8(vec))));
     366                 :           2 :                 buf += sizeof(uint8x16_t);
     367                 :             : 
     368                 :           2 :                 vec = vld1q_u8((const uint8 *) buf);
     369                 :           2 :                 accum2 = vpadalq_u32(accum2, vpaddlq_u16(vpaddlq_u8(vcntq_u8(vec))));
     370                 :           2 :                 buf += sizeof(uint8x16_t);
     371                 :             : 
     372                 :           2 :                 bytes -= bytes_per_iteration;
     373                 :           2 :         }
     374                 :             : 
     375                 :             :         /*
     376                 :             :          * Add the accumulators.
     377                 :             :          */
     378                 :           4 :         popcnt += vaddvq_u64(vaddq_u64(accum1, accum2));
     379                 :           4 :         popcnt += vaddvq_u64(vaddq_u64(accum3, accum4));
     380                 :             : 
     381                 :             :         /*
     382                 :             :          * Process remaining 8-byte blocks.
     383                 :             :          */
     384         [ +  + ]:          12 :         for (; bytes >= sizeof(uint64); bytes -= sizeof(uint64))
     385                 :             :         {
     386                 :           8 :                 popcnt += pg_popcount64(*((uint64 *) buf));
     387                 :           8 :                 buf += sizeof(uint64);
     388                 :           8 :         }
     389                 :             : 
     390                 :             :         /*
     391                 :             :          * Process any remaining data byte-by-byte.
     392                 :             :          */
     393         [ +  + ]:          24 :         while (bytes--)
     394                 :          20 :                 popcnt += pg_number_of_ones[(unsigned char) *buf++];
     395                 :             : 
     396                 :           8 :         return popcnt;
     397                 :           4 : }
     398                 :             : 
     399                 :             : /*
     400                 :             :  * pg_popcount_masked_neon
     401                 :             :  *              Returns number of 1 bits in buf after applying the mask to each byte
     402                 :             :  */
     403                 :             : static uint64
     404                 :         954 : pg_popcount_masked_neon(const char *buf, int bytes, bits8 mask)
     405                 :             : {
     406                 :         954 :         uint8x16_t      vec,
     407                 :         954 :                                 maskv = vdupq_n_u8(mask);
     408                 :        2862 :         uint64x2_t      accum1 = vdupq_n_u64(0),
     409                 :         954 :                                 accum2 = vdupq_n_u64(0),
     410                 :         954 :                                 accum3 = vdupq_n_u64(0),
     411                 :         954 :                                 accum4 = vdupq_n_u64(0);
     412                 :         954 :         uint32          bytes_per_iteration = 4 * sizeof(uint8x16_t);
     413                 :         954 :         uint64          popcnt = 0,
     414                 :         954 :                                 mask64 = ~UINT64CONST(0) / 0xFF * mask;
     415                 :             : 
     416                 :             :         /*
     417                 :             :          * For better instruction-level parallelism, each loop iteration operates
     418                 :             :          * on a block of four registers.
     419                 :             :          */
     420         [ +  + ]:      122112 :         for (; bytes >= bytes_per_iteration; bytes -= bytes_per_iteration)
     421                 :             :         {
     422                 :      121158 :                 vec = vandq_u8(vld1q_u8((const uint8 *) buf), maskv);
     423                 :      121158 :                 accum1 = vpadalq_u32(accum1, vpaddlq_u16(vpaddlq_u8(vcntq_u8(vec))));
     424                 :      121158 :                 buf += sizeof(uint8x16_t);
     425                 :             : 
     426                 :      121158 :                 vec = vandq_u8(vld1q_u8((const uint8 *) buf), maskv);
     427                 :      121158 :                 accum2 = vpadalq_u32(accum2, vpaddlq_u16(vpaddlq_u8(vcntq_u8(vec))));
     428                 :      121158 :                 buf += sizeof(uint8x16_t);
     429                 :             : 
     430                 :      121158 :                 vec = vandq_u8(vld1q_u8((const uint8 *) buf), maskv);
     431                 :      121158 :                 accum3 = vpadalq_u32(accum3, vpaddlq_u16(vpaddlq_u8(vcntq_u8(vec))));
     432                 :      121158 :                 buf += sizeof(uint8x16_t);
     433                 :             : 
     434                 :      121158 :                 vec = vandq_u8(vld1q_u8((const uint8 *) buf), maskv);
     435                 :      121158 :                 accum4 = vpadalq_u32(accum4, vpaddlq_u16(vpaddlq_u8(vcntq_u8(vec))));
     436                 :      121158 :                 buf += sizeof(uint8x16_t);
     437                 :      121158 :         }
     438                 :             : 
     439                 :             :         /*
     440                 :             :          * If enough data remains, do another iteration on a block of two
     441                 :             :          * registers.
     442                 :             :          */
     443                 :         954 :         bytes_per_iteration = 2 * sizeof(uint8x16_t);
     444         [ -  + ]:         954 :         if (bytes >= bytes_per_iteration)
     445                 :             :         {
     446                 :         954 :                 vec = vandq_u8(vld1q_u8((const uint8 *) buf), maskv);
     447                 :         954 :                 accum1 = vpadalq_u32(accum1, vpaddlq_u16(vpaddlq_u8(vcntq_u8(vec))));
     448                 :         954 :                 buf += sizeof(uint8x16_t);
     449                 :             : 
     450                 :         954 :                 vec = vandq_u8(vld1q_u8((const uint8 *) buf), maskv);
     451                 :         954 :                 accum2 = vpadalq_u32(accum2, vpaddlq_u16(vpaddlq_u8(vcntq_u8(vec))));
     452                 :         954 :                 buf += sizeof(uint8x16_t);
     453                 :             : 
     454                 :         954 :                 bytes -= bytes_per_iteration;
     455                 :         954 :         }
     456                 :             : 
     457                 :             :         /*
     458                 :             :          * Add the accumulators.
     459                 :             :          */
     460                 :         954 :         popcnt += vaddvq_u64(vaddq_u64(accum1, accum2));
     461                 :         954 :         popcnt += vaddvq_u64(vaddq_u64(accum3, accum4));
     462                 :             : 
     463                 :             :         /*
     464                 :             :          * Process remaining 8-byte blocks.
     465                 :             :          */
     466         [ +  + ]:        1908 :         for (; bytes >= sizeof(uint64); bytes -= sizeof(uint64))
     467                 :             :         {
     468                 :         954 :                 popcnt += pg_popcount64(*((uint64 *) buf) & mask64);
     469                 :         954 :                 buf += sizeof(uint64);
     470                 :         954 :         }
     471                 :             : 
     472                 :             :         /*
     473                 :             :          * Process any remaining data byte-by-byte.
     474                 :             :          */
     475         [ -  + ]:         954 :         while (bytes--)
     476                 :           0 :                 popcnt += pg_number_of_ones[(unsigned char) *buf++ & mask];
     477                 :             : 
     478                 :        1908 :         return popcnt;
     479                 :         954 : }
     480                 :             : 
     481                 :             : #endif                                                  /* USE_NEON */
        

Generated by: LCOV version 2.3.2-1