Repository: valkey-io/valkey
File: src/bitops.c (C)

Code before:
        aux5 = aux5 - ((aux5 >> 1) & 0x55555555);
        aux5 = (aux5 & 0x33333333) + ((aux5 >> 2) & 0x33333333);
        aux6 = aux6 - ((aux6 >> 1) & 0x55555555);
        aux6 = (aux6 & 0x33333333) + ((aux6 >> 2) & 0x33333333);
        aux7 = aux7 - ((aux7 >> 1) & 0x55555555);
        aux7 = (aux7 & 0x33333333) + ((aux7 >> 2) & 0x33333333);
        bits += ((((aux1 + (aux1 >> 4)) & 0x0F0F0F0F) + ((aux2 + (aux2 >> 4)) & 0x0F0F0F0F) +
                  ((aux3 + (aux3 >> 4)) & 0x0F0F0F0F) + ((aux4 + (aux4 >> 4)) & 0x0F0F0F0F) +
                  ((aux5 + (aux5 >> 4)) & 0x0F0F0F0F) + ((aux6 + (aux6 >> 4)) & 0x0F0F0F0F) +
                  ((aux7 + (aux7 >> 4)) & 0x0F0F0F0F)) *
                 0x01010101) >>
                24;
    }
    /* Count the remaining bytes. */
    p = (unsigned char *)p4;
    while (count--) bits += bitsinbyte[*p++];
    return bits;
}

#if defined(__aarch64__)
#include <arm_neon.h>

/**
 *  SIMD version of popcount for ARM NEON.
 *  Processes data in 64-byte NEON batches, falls back to scalar for tail.
 */
long long popcountNEON(void *s, long n) {
    long long t = 0;
    uint8_t *p = (uint8_t *)s;;
    const uint8_t *e = p + n;

    /* Process 64-byte blocks using unrolled loop (4 x 16-byte vectors) */
    for (; p <= e - 64; p += 64) {
        /* Load 4 vector registers (16 bytes each) */
        uint8x16_t v0 = vld1q_u8(p);
        uint8x16_t v1 = vld1q_u8(p + 16);
        uint8x16_t v2 = vld1q_u8(p + 32);
        uint8x16_t v3 = vld1q_u8(p + 48);

        /* Count bits in each byte and sum vectors */
        uint8x16_t s1 = vaddq_u8(vcntq_u8(v0), vcntq_u8(v1));
        uint8x16_t s2 = vaddq_u8(vcntq_u8(v2), vcntq_u8(v3));
        uint8x16_t s0 = vaddq_u8(s1, s2);

        /* Sum all bytes in the final vector */
        uint16x8_t sc = vpaddlq_u8(s0);     // 16x u8 → 8x u16 (pairwise add)
        uint32_t t1 = vaddvq_u16(sc);
        t += t1;
    }

    /* Process remaining 16-byte chunks */

Review comment (performance):
We don't use doxygen comments. This very compact style is the most common:

```suggestion
/*  SIMD version of popcount for ARM NEON.
 *  Processes data in 64-byte NEON batches, falls back to scalar for tail. */
```

Code after:
        aux5 = aux5 - ((aux5 >> 1) & 0x55555555);
        aux5 = (aux5 & 0x33333333) + ((aux5 >> 2) & 0x33333333);
        aux6 = aux6 - ((aux6 >> 1) & 0x55555555);
        aux6 = (aux6 & 0x33333333) + ((aux6 >> 2) & 0x33333333);
        aux7 = aux7 - ((aux7 >> 1) & 0x55555555);
        aux7 = (aux7 & 0x33333333) + ((aux7 >> 2) & 0x33333333);
        bits += ((((aux1 + (aux1 >> 4)) & 0x0F0F0F0F) + ((aux2 + (aux2 >> 4)) & 0x0F0F0F0F) +
                  ((aux3 + (aux3 >> 4)) & 0x0F0F0F0F) + ((aux4 + (aux4 >> 4)) & 0x0F0F0F0F) +
                  ((aux5 + (aux5 >> 4)) & 0x0F0F0F0F) + ((aux6 + (aux6 >> 4)) & 0x0F0F0F0F) +
                  ((aux7 + (aux7 >> 4)) & 0x0F0F0F0F)) *
                 0x01010101) >>
                24;
    }
    /* Count the remaining bytes. */
    p = (unsigned char *)p4;
    while (count--) bits += bitsinbyte[*p++];
    return bits;
}

#if defined(__aarch64__)
#include <arm_neon.h>

/*  SIMD version of popcount for ARM NEON.
 *  Processes data in 64-byte NEON batches, falls back to scalar for tail. */
long long popcountNEON(void *s, long n) {
    long long t = 0;
    uint8_t *p = (uint8_t *)s;
    ;
    const uint8_t *e = p + n;

    /* Process 64-byte blocks using unrolled loop (4 x 16-byte vectors) */
    for (; p <= e - 64; p += 64) {
        /* Load 4 vector registers (16 bytes each) */
        uint8x16_t v0 = vld1q_u8(p);
        uint8x16_t v1 = vld1q_u8(p + 16);
        uint8x16_t v2 = vld1q_u8(p + 32);
        uint8x16_t v3 = vld1q_u8(p + 48);

        /* Count bits in each byte and sum vectors */
        uint8x16_t s1 = vaddq_u8(vcntq_u8(v0), vcntq_u8(v1));
        uint8x16_t s2 = vaddq_u8(vcntq_u8(v2), vcntq_u8(v3));
        uint8x16_t s0 = vaddq_u8(s1, s2);

        /* Sum all bytes in the final vector */
        uint16x8_t sc = vpaddlq_u8(s0); // 16x u8 -> 8x u16 (pairwise add)
        uint32_t t1 = vaddvq_u16(sc);
        t += t1;
    }

    /* Process remaining 16-byte chunks */
    for (; p + 16 <= e; p += 16) {