unsigned crc_32(const void *src, unsigned len, unsigned crc32) {
  const unsigned char *buf = (const unsigned char *)src;
  static const unsigned crc32_lookup[16] = {
      0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
      0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
      0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD};
  unsigned char byte;
  unsigned t;
  while (len--) {
    byte = *buf++;
    t = crc32 >> 28;
    t ^= byte >> 4;
    crc32 <<= 4;
    crc32 ^= crc32_lookup[t];
    t = crc32 >> 28;
    t ^= byte & 0x0F;
    crc32 <<= 4;
    crc32 ^= crc32_lookup[t];
  }
  return crc32;
}


x86 assembly (clang, -O0):
<crc_32>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %esi,-0xc(%rbp)
mov    %edx,-0x10(%rbp)
mov    -0x8(%rbp),%rax
mov    %rax,-0x18(%rbp)
mov    -0xc(%rbp),%eax
mov    %eax,%ecx
add    $0xffffffff,%ecx
mov    %ecx,-0xc(%rbp)
cmp    $0x0,%eax
je     11ab <crc_32+0xab>
mov    -0x18(%rbp),%rax
mov    %rax,%rcx
add    $0x1,%rcx
mov    %rcx,-0x18(%rbp)
mov    (%rax),%al
mov    %al,-0x19(%rbp)
mov    -0x10(%rbp),%eax
shr    $0x1c,%eax
mov    %eax,-0x20(%rbp)
movzbl -0x19(%rbp),%eax
sar    $0x4,%eax
xor    -0x20(%rbp),%eax
mov    %eax,-0x20(%rbp)
mov    -0x10(%rbp),%eax
shl    $0x4,%eax
mov    %eax,-0x10(%rbp)
mov    -0x20(%rbp),%eax
mov    %eax,%ecx
lea    0xe97(%rip),%rax
mov    (%rax,%rcx,4),%eax
xor    -0x10(%rbp),%eax
mov    %eax,-0x10(%rbp)
mov    -0x10(%rbp),%eax
shr    $0x1c,%eax
mov    %eax,-0x20(%rbp)
movzbl -0x19(%rbp),%eax
and    $0xf,%eax
xor    -0x20(%rbp),%eax
mov    %eax,-0x20(%rbp)
mov    -0x10(%rbp),%eax
shl    $0x4,%eax
mov    %eax,-0x10(%rbp)
mov    -0x20(%rbp),%eax
mov    %eax,%ecx
lea    0xe63(%rip),%rax
mov    (%rax,%rcx,4),%eax
xor    -0x10(%rbp),%eax
mov    %eax,-0x10(%rbp)
jmp    1116 <crc_32+0x16>
mov    -0x10(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<crc_32>:
mov    %edx,%eax
test   %esi,%esi
je     1152 <crc_32+0x52>
mov    %esi,%r8d
xor    %r10d,%r10d
lea    0xeed(%rip),%r9
cs nopw 0x0(%rax,%rax,1)
nopl   (%rax)
movzbl (%rdi,%r10,1),%edx
mov    %eax,%esi
shr    $0x1c,%esi
mov    %edx,%ecx
shr    $0x4,%ecx
xor    %esi,%ecx
shl    $0x4,%eax
xor    (%r9,%rcx,4),%eax
mov    %eax,%ecx
shr    $0x1c,%ecx
and    $0xf,%edx
xor    %ecx,%edx
shl    $0x4,%eax
xor    (%r9,%rdx,4),%eax
add    $0x1,%r10
cmp    %r10d,%r8d
jne    1120 <crc_32+0x20>
ret

LLVM IR (-O0):
@crc_32.crc32_lookup = internal constant [16 x i32] [i32 0, i32 79764919, i32 159529838, i32 222504665, i32 319059676, i32 398814059, i32 445009330, i32 507990021, i32 638119352, i32 583659535, i32 797628118, i32 726387553, i32 890018660, i32 835552979, i32 1015980042, i32 944750013]
define i32 @crc_32(i8* %0, i32 %1, i32 %2) {
%4 = alloca i8*
%5 = alloca i32
%6 = alloca i32
%7 = alloca i8*
%8 = alloca i8
%9 = alloca i32
store i8* %0, i8** %4
store i32 %1, i32* %5
store i32 %2, i32* %6
%10 = load i8*, i8** %4
store i8* %10, i8** %7
br label %11
11: ; preds = %15, %3
%12 = load i32, i32* %5
%13 = add i32 %12, -1
store i32 %13, i32* %5
%14 = icmp ne i32 %12, 0
br i1 %14, label %15, label %49
15: ; preds = %11
%16 = load i8*, i8** %7
%17 = getelementptr inbounds i8, i8* %16, i32 1
store i8* %17, i8** %7
%18 = load i8, i8* %16
store i8 %18, i8* %8
%19 = load i32, i32* %6
%20 = lshr i32 %19, 28
store i32 %20, i32* %9
%21 = load i8, i8* %8
%22 = zext i8 %21 to i32
%23 = ashr i32 %22, 4
%24 = load i32, i32* %9
%25 = xor i32 %24, %23
store i32 %25, i32* %9
%26 = load i32, i32* %6
%27 = shl i32 %26, 4
store i32 %27, i32* %6
%28 = load i32, i32* %9
%29 = zext i32 %28 to i64
%30 = getelementptr inbounds [16 x i32], [16 x i32]* @crc_32.crc32_lookup, i64 0, i64 %29
%31 = load i32, i32* %30
%32 = load i32, i32* %6
%33 = xor i32 %32, %31
store i32 %33, i32* %6
%34 = load i32, i32* %6
%35 = lshr i32 %34, 28
store i32 %35, i32* %9
%36 = load i8, i8* %8
%37 = zext i8 %36 to i32
%38 = and i32 %37, 15
%39 = load i32, i32* %9
%40 = xor i32 %39, %38
store i32 %40, i32* %9
%41 = load i32, i32* %6
%42 = shl i32 %41, 4
store i32 %42, i32* %6
%43 = load i32, i32* %9
%44 = zext i32 %43 to i64
%45 = getelementptr inbounds [16 x i32], [16 x i32]* @crc_32.crc32_lookup, i64 0, i64 %44
%46 = load i32, i32* %45
%47 = load i32, i32* %6
%48 = xor i32 %47, %46
store i32 %48, i32* %6
br label %11
49: ; preds = %11
%50 = load i32, i32* %6
ret i32 %50
}

LLVM IR (-O2):
@crc_32.crc32_lookup = internal unnamed_addr constant [16 x i32] [i32 0, i32 79764919, i32 159529838, i32 222504665, i32 319059676, i32 398814059, i32 445009330, i32 507990021, i32 638119352, i32 583659535, i32 797628118, i32 726387553, i32 890018660, i32 835552979, i32 1015980042, i32 944750013]
define i32 @crc_32(i8* nocapture %0, i32 %1, i32 %2) {
%4 = icmp eq i32 %1, 0
br i1 %4, label %30, label %5
5: ; preds = %3, %5
%6 = phi i32 [ %9, %5 ], [ %1, %3 ]
%7 = phi i32 [ %28, %5 ], [ %2, %3 ]
%8 = phi i8* [ %10, %5 ], [ %0, %3 ]
%9 = add i32 %6, -1
%10 = getelementptr inbounds i8, i8* %8, i64 1
%11 = load i8, i8* %8
%12 = lshr i32 %7, 28
%13 = zext i8 %11 to i32
%14 = lshr i32 %13, 4
%15 = xor i32 %14, %12
%16 = shl i32 %7, 4
%17 = zext i32 %15 to i64
%18 = getelementptr inbounds [16 x i32], [16 x i32]* @crc_32.crc32_lookup, i64 0, i64 %17
%19 = load i32, i32* %18
%20 = xor i32 %19, %16
%21 = lshr i32 %20, 28
%22 = and i32 %13, 15
%23 = xor i32 %21, %22
%24 = shl i32 %20, 4
%25 = zext i32 %23 to i64
%26 = getelementptr inbounds [16 x i32], [16 x i32]* @crc_32.crc32_lookup, i64 0, i64 %25
%27 = load i32, i32* %26
%28 = xor i32 %24, %27
%29 = icmp eq i32 %9, 0
br i1 %29, label %30, label %5
30: ; preds = %5, %3
%31 = phi i32 [ %2, %3 ], [ %28, %5 ]
ret i32 %31
}