int lut_4bit(long v) {
  static int lut[16] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
  int count = 0;
  int nybble = 0;
  for (nybble = 0; nybble < sizeof(v) * 2; nybble++) {
    count += lut[v & 0x0f];
    v >>= 4;
  }
  return count;
}


x86 assembly (clang, -O0):
<lut_4bit>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
movl   $0x0,-0xc(%rbp)
movl   $0x0,-0x10(%rbp)
movl   $0x0,-0x10(%rbp)
movslq -0x10(%rbp),%rax
cmp    $0x10,%rax
jae    115d <lut_4bit+0x5d>
mov    -0x8(%rbp),%rcx
and    $0xf,%rcx
lea    0x2ef6(%rip),%rax
mov    (%rax,%rcx,4),%eax
add    -0xc(%rbp),%eax
mov    %eax,-0xc(%rbp)
mov    -0x8(%rbp),%rax
sar    $0x4,%rax
mov    %rax,-0x8(%rbp)
mov    -0x10(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x10(%rbp)
jmp    111d <lut_4bit+0x1d>
mov    -0xc(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<lut_4bit>:
mov    %edi,%edx
and    $0xf,%edx
lea    0xef4(%rip),%rcx
mov    %rdi,%rax
shr    $0x2,%rax
and    $0x3c,%eax
mov    (%rax,%rcx,1),%eax
add    (%rcx,%rdx,4),%eax
mov    %rdi,%rdx
shr    $0x6,%rdx
and    $0x3c,%edx
add    (%rdx,%rcx,1),%eax
mov    %rdi,%rdx
shr    $0xa,%rdx
and    $0x3c,%edx
add    (%rdx,%rcx,1),%eax
mov    %rdi,%rdx
shr    $0xe,%rdx
and    $0x3c,%edx
add    (%rdx,%rcx,1),%eax
mov    %rdi,%rdx
shr    $0x12,%rdx
and    $0x3c,%edx
add    (%rdx,%rcx,1),%eax
mov    %rdi,%rdx
shr    $0x16,%rdx
and    $0x3c,%edx
add    (%rdx,%rcx,1),%eax
mov    %rdi,%rdx
shr    $0x1a,%rdx
and    $0x3c,%edx
add    (%rdx,%rcx,1),%eax
mov    %rdi,%rdx
shr    $0x1e,%rdx
and    $0x3c,%edx
add    (%rdx,%rcx,1),%eax
mov    %rdi,%rdx
shr    $0x22,%rdx
and    $0x3c,%edx
add    (%rdx,%rcx,1),%eax
mov    %rdi,%rdx
shr    $0x26,%rdx
and    $0x3c,%edx
add    (%rdx,%rcx,1),%eax
mov    %rdi,%rdx
shr    $0x2a,%rdx
and    $0x3c,%edx
add    (%rdx,%rcx,1),%eax
mov    %rdi,%rdx
shr    $0x2e,%rdx
and    $0x3c,%edx
add    (%rdx,%rcx,1),%eax
mov    %rdi,%rdx
shr    $0x32,%rdx
and    $0x3c,%edx
add    (%rdx,%rcx,1),%eax
mov    %rdi,%rdx
shr    $0x36,%rdx
and    $0x3c,%edx
add    (%rdx,%rcx,1),%eax
shr    $0x3c,%rdi
add    (%rcx,%rdi,4),%eax
ret

LLVM IR (-O0):
@lut_4bit.lut = internal global [16 x i32] [i32 0, i32 1, i32 1, i32 2, i32 1, i32 2, i32 2, i32 3, i32 1, i32 2, i32 2, i32 3, i32 2, i32 3, i32 3, i32 4]
define i32 @lut_4bit(i64 %0) {
%2 = alloca i64
%3 = alloca i32
%4 = alloca i32
store i64 %0, i64* %2
store i32 0, i32* %3
store i32 0, i32* %4
store i32 0, i32* %4
br label %5
5: ; preds = %18, %1
%6 = load i32, i32* %4
%7 = sext i32 %6 to i64
%8 = icmp ult i64 %7, 16
br i1 %8, label %9, label %21
9: ; preds = %5
%10 = load i64, i64* %2
%11 = and i64 %10, 15
%12 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %11
%13 = load i32, i32* %12
%14 = load i32, i32* %3
%15 = add nsw i32 %14, %13
store i32 %15, i32* %3
%16 = load i64, i64* %2
%17 = ashr i64 %16, 4
store i64 %17, i64* %2
br label %18
18: ; preds = %9
%19 = load i32, i32* %4
%20 = add nsw i32 %19, 1
store i32 %20, i32* %4
br label %5
21: ; preds = %5
%22 = load i32, i32* %3
ret i32 %22
}

LLVM IR (-O2):
@lut_4bit.lut = internal unnamed_addr constant [16 x i32] [i32 0, i32 1, i32 1, i32 2, i32 1, i32 2, i32 2, i32 3, i32 1, i32 2, i32 2, i32 3, i32 2, i32 3, i32 3, i32 4]
define i32 @lut_4bit(i64 %0) {
%2 = and i64 %0, 15
%3 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %2
%4 = load i32, i32* %3
%5 = lshr i64 %0, 4
%6 = and i64 %5, 15
%7 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %6
%8 = load i32, i32* %7
%9 = add nsw i32 %8, %4
%10 = lshr i64 %0, 8
%11 = and i64 %10, 15
%12 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %11
%13 = load i32, i32* %12
%14 = add nsw i32 %13, %9
%15 = lshr i64 %0, 12
%16 = and i64 %15, 15
%17 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %16
%18 = load i32, i32* %17
%19 = add nsw i32 %18, %14
%20 = lshr i64 %0, 16
%21 = and i64 %20, 15
%22 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %21
%23 = load i32, i32* %22
%24 = add nsw i32 %23, %19
%25 = lshr i64 %0, 20
%26 = and i64 %25, 15
%27 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %26
%28 = load i32, i32* %27
%29 = add nsw i32 %28, %24
%30 = lshr i64 %0, 24
%31 = and i64 %30, 15
%32 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %31
%33 = load i32, i32* %32
%34 = add nsw i32 %33, %29
%35 = lshr i64 %0, 28
%36 = and i64 %35, 15
%37 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %36
%38 = load i32, i32* %37
%39 = add nsw i32 %38, %34
%40 = lshr i64 %0, 32
%41 = and i64 %40, 15
%42 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %41
%43 = load i32, i32* %42
%44 = add nsw i32 %43, %39
%45 = lshr i64 %0, 36
%46 = and i64 %45, 15
%47 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %46
%48 = load i32, i32* %47
%49 = add nsw i32 %48, %44
%50 = lshr i64 %0, 40
%51 = and i64 %50, 15
%52 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %51
%53 = load i32, i32* %52
%54 = add nsw i32 %53, %49
%55 = lshr i64 %0, 44
%56 = and i64 %55, 15
%57 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %56
%58 = load i32, i32* %57
%59 = add nsw i32 %58, %54
%60 = lshr i64 %0, 48
%61 = and i64 %60, 15
%62 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %61
%63 = load i32, i32* %62
%64 = add nsw i32 %63, %59
%65 = lshr i64 %0, 52
%66 = and i64 %65, 15
%67 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %66
%68 = load i32, i32* %67
%69 = add nsw i32 %68, %64
%70 = lshr i64 %0, 56
%71 = and i64 %70, 15
%72 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %71
%73 = load i32, i32* %72
%74 = add nsw i32 %73, %69
%75 = lshr i64 %0, 60
%76 = getelementptr inbounds [16 x i32], [16 x i32]* @lut_4bit.lut, i64 0, i64 %75
%77 = load i32, i32* %76
%78 = add nsw i32 %77, %74
ret i32 %78
}