Skip to content
Assembly

Bit Manipulation: popcount, ctz, abs

Use BMI/ABM instructions for branchless bit operations.

By EZ4Code Team
bitwisebmibranchless

Code

; popcount(x) -> number of set bits   rdi=x, result in rax
global popcount
popcount:
    mov     eax, edi
    popcnt  eax, eax        ; HW popcount (SSE4.2)
    ret

; ctz(x) -> count of trailing zeros  (BSF)
global ctz
ctz:
    bsf     eax, edi        ; bit scan forward -> index of lowest set bit
    ret

; clz(x) -> count of leading zeros   (LZCNT / BSR)
global clz
clz:
    lzcnt   eax, edi
    ret

; abs(x) branchless:  mask = x >> 31;  result = (x ^ mask) - mask
global abs_int
abs_int:
    mov     eax, edi
    cdq                 ; edx = sign extension of eax (all 1s if neg)
    xor     eax, edx    ; flip bits if negative
    sub     eax, edx    ; add 1 if negative  -> |x|
    ret

; Bit reversal (BSWAP for byte order)
global bswap_demo
bswap_demo:
    mov     eax, 0x11223344
    bswap   eax          ; eax = 0x44332211
    ret

Explanation

Modern x86 has hardware instructions for common bit operations: popcnt (population count), bsf/bsr (bit scan forward/reverse), lzcnt/tzcnt (leading/trailing zero count), and bswap (byte-swap for endianness). The branchless abs uses the sign-extension trick: cdq fills edx with the sign bit, XOR flips the bits if negative, and SUB adds 1 to complete two's-complement negation — no branches, no mispredictions.

More Assembly Snippets