unsigned short CRC16(unsigned char *msg, unsigned short length) {
  unsigned short crc = 0xFFFF;
  unsigned short i, j;
  unsigned short lsb;
  for (i = 0; i < length; i++) {
    crc ^= msg[i];
    for (j = 0; j < 8; j++) {
      lsb = crc & 0x1;
      crc = crc >> 1;
      if (lsb)
        crc ^= 0xA001;
    }
  }
  return crc;
}


x86 assembly (clang, -O0):
<CRC16>:
push   %rbp
mov    %rsp,%rbp
mov    %si,%ax
mov    %rdi,-0x8(%rbp)
mov    %ax,-0xa(%rbp)
movw   $0xffff,-0xc(%rbp)
movw   $0x0,-0xe(%rbp)
movzwl -0xe(%rbp),%eax
movzwl -0xa(%rbp),%ecx
cmp    %ecx,%eax
jge    11ae <CRC16+0xae>
mov    -0x8(%rbp),%rax
movzwl -0xe(%rbp),%ecx
movzbl (%rax,%rcx,1),%ecx
movzwl -0xc(%rbp),%eax
xor    %ecx,%eax
mov    %ax,-0xc(%rbp)
movw   $0x0,-0x10(%rbp)
movzwl -0x10(%rbp),%eax
cmp    $0x8,%eax
jge    1198 <CRC16+0x98>
movzwl -0xc(%rbp),%eax
and    $0x1,%eax
mov    %ax,-0x12(%rbp)
movzwl -0xc(%rbp),%eax
sar    $0x1,%eax
mov    %ax,-0xc(%rbp)
cmpw   $0x0,-0x12(%rbp)
je     1182 <CRC16+0x82>
movzwl -0xc(%rbp),%eax
xor    $0xa001,%eax
mov    %ax,-0xc(%rbp)
jmp    1187 <CRC16+0x87>
mov    -0x10(%rbp),%ax
add    $0x1,%ax
mov    %ax,-0x10(%rbp)
jmp    1147 <CRC16+0x47>
jmp    119d <CRC16+0x9d>
mov    -0xe(%rbp),%ax
add    $0x1,%ax
mov    %ax,-0xe(%rbp)
jmp    111b <CRC16+0x1b>
movzwl -0xc(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<CRC16>:
test   %esi,%esi
je     11ce <CRC16+0xce>
movzwl %si,%r8d
mov    $0xffff,%ax
xor    %edx,%edx
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax)
movzbl (%rdi,%rdx,1),%esi
xor    %esi,%eax
movzwl %ax,%ecx
shr    %ecx
mov    %ecx,%esi
xor    $0xffffa001,%esi
test   $0x1,%al
cmove  %ecx,%esi
movzwl %si,%eax
shr    %eax
mov    %eax,%ecx
xor    $0xffffa001,%ecx
test   $0x1,%sil
cmove  %eax,%ecx
movzwl %cx,%eax
shr    %eax
mov    %eax,%esi
xor    $0xffffa001,%esi
test   $0x1,%cl
cmove  %eax,%esi
movzwl %si,%eax
shr    %eax
mov    %eax,%ecx
xor    $0xffffa001,%ecx
test   $0x1,%sil
cmove  %eax,%ecx
movzwl %cx,%eax
shr    %eax
mov    %eax,%esi
xor    $0xffffa001,%esi
test   $0x1,%cl
cmove  %eax,%esi
movzwl %si,%eax
shr    %eax
mov    %eax,%ecx
xor    $0xffffa001,%ecx
test   $0x1,%sil
cmove  %eax,%ecx
movzwl %cx,%eax
shr    %eax
mov    %eax,%esi
xor    $0xffffa001,%esi
test   $0x1,%cl
cmove  %eax,%esi
movzwl %si,%ecx
shr    %ecx
mov    %ecx,%eax
xor    $0xffffa001,%eax
test   $0x1,%sil
cmove  %ecx,%eax
add    $0x1,%rdx
cmp    %rdx,%r8
jne    1120 <CRC16+0x20>
ret
mov    $0xffff,%ax
ret

LLVM IR (-O0):
define zeroext i16 @CRC16(i8* %0, i16 zeroext %1) {
%3 = alloca i8*
%4 = alloca i16
%5 = alloca i16
%6 = alloca i16
%7 = alloca i16
%8 = alloca i16
store i8* %0, i8** %3
store i16 %1, i16* %4
store i16 -1, i16* %5
store i16 0, i16* %6
br label %9
9: ; preds = %51, %2
%10 = load i16, i16* %6
%11 = zext i16 %10 to i32
%12 = load i16, i16* %4
%13 = zext i16 %12 to i32
%14 = icmp slt i32 %11, %13
br i1 %14, label %15, label %54
15: ; preds = %9
%16 = load i8*, i8** %3
%17 = load i16, i16* %6
%18 = zext i16 %17 to i64
%19 = getelementptr inbounds i8, i8* %16, i64 %18
%20 = load i8, i8* %19
%21 = zext i8 %20 to i32
%22 = load i16, i16* %5
%23 = zext i16 %22 to i32
%24 = xor i32 %23, %21
%25 = trunc i32 %24 to i16
store i16 %25, i16* %5
store i16 0, i16* %7
br label %26
26: ; preds = %47, %15
%27 = load i16, i16* %7
%28 = zext i16 %27 to i32
%29 = icmp slt i32 %28, 8
br i1 %29, label %30, label %50
30: ; preds = %26
%31 = load i16, i16* %5
%32 = zext i16 %31 to i32
%33 = and i32 %32, 1
%34 = trunc i32 %33 to i16
store i16 %34, i16* %8
%35 = load i16, i16* %5
%36 = zext i16 %35 to i32
%37 = ashr i32 %36, 1
%38 = trunc i32 %37 to i16
store i16 %38, i16* %5
%39 = load i16, i16* %8
%40 = icmp ne i16 %39, 0
br i1 %40, label %41, label %46
41: ; preds = %30
%42 = load i16, i16* %5
%43 = zext i16 %42 to i32
%44 = xor i32 %43, 40961
%45 = trunc i32 %44 to i16
store i16 %45, i16* %5
br label %46
46: ; preds = %41, %30
br label %47
47: ; preds = %46
%48 = load i16, i16* %7
%49 = add i16 %48, 1
store i16 %49, i16* %7
br label %26
50: ; preds = %26
br label %51
51: ; preds = %50
%52 = load i16, i16* %6
%53 = add i16 %52, 1
store i16 %53, i16* %6
br label %9
54: ; preds = %9
%55 = load i16, i16* %5
ret i16 %55
}

LLVM IR (-O2):
define zeroext i16 @CRC16(i8* nocapture %0, i16 zeroext %1) {
%3 = icmp eq i16 %1, 0
br i1 %3, label %55, label %4
4: ; preds = %2
%5 = zext i16 %1 to i64
br label %6
6: ; preds = %4, %6
%7 = phi i64 [ 0, %4 ], [ %53, %6 ]
%8 = phi i16 [ -1, %4 ], [ %52, %6 ]
%9 = getelementptr inbounds i8, i8* %0, i64 %7
%10 = load i8, i8* %9
%11 = zext i8 %10 to i16
%12 = xor i16 %8, %11
%13 = and i16 %12, 1
%14 = lshr i16 %12, 1
%15 = icmp eq i16 %13, 0
%16 = xor i16 %14, -24575
%17 = select i1 %15, i16 %14, i16 %16
%18 = and i16 %17, 1
%19 = lshr i16 %17, 1
%20 = icmp eq i16 %18, 0
%21 = xor i16 %19, -24575
%22 = select i1 %20, i16 %19, i16 %21
%23 = and i16 %22, 1
%24 = lshr i16 %22, 1
%25 = icmp eq i16 %23, 0
%26 = xor i16 %24, -24575
%27 = select i1 %25, i16 %24, i16 %26
%28 = and i16 %27, 1
%29 = lshr i16 %27, 1
%30 = icmp eq i16 %28, 0
%31 = xor i16 %29, -24575
%32 = select i1 %30, i16 %29, i16 %31
%33 = and i16 %32, 1
%34 = lshr i16 %32, 1
%35 = icmp eq i16 %33, 0
%36 = xor i16 %34, -24575
%37 = select i1 %35, i16 %34, i16 %36
%38 = and i16 %37, 1
%39 = lshr i16 %37, 1
%40 = icmp eq i16 %38, 0
%41 = xor i16 %39, -24575
%42 = select i1 %40, i16 %39, i16 %41
%43 = and i16 %42, 1
%44 = lshr i16 %42, 1
%45 = icmp eq i16 %43, 0
%46 = xor i16 %44, -24575
%47 = select i1 %45, i16 %44, i16 %46
%48 = and i16 %47, 1
%49 = lshr i16 %47, 1
%50 = icmp eq i16 %48, 0
%51 = xor i16 %49, -24575
%52 = select i1 %50, i16 %49, i16 %51
%53 = add nuw nsw i64 %7, 1
%54 = icmp eq i64 %53, %5
br i1 %54, label %55, label %6
55: ; preds = %6, %2
%56 = phi i16 [ -1, %2 ], [ %52, %6 ]
ret i16 %56
}