unsigned short checksum_update(unsigned short old_sum, unsigned short *old_data,
                               short old_len, unsigned short *new_data,
                               short new_len) {
  unsigned int sum;
  sum = ~old_sum & 0xffff;
  while (old_len) {
    sum -= *old_data++;
    if (sum & 0x80000000) {
      sum--;
      sum &= 0xffff;
    }
    old_len -= 2;
  }
  while (new_len) {
    sum += *new_data++;
    if (sum & 0x00010000) {
      sum++;
      sum &= 0xffff;
    }
    new_len -= 2;
  }
  return ~sum & 0xffff;
}


x86 assembly (clang, -O0):
<checksum_update>:
push   %rbp
mov    %rsp,%rbp
mov    %r8w,%ax
mov    %di,-0x2(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %dx,-0x12(%rbp)
mov    %rcx,-0x20(%rbp)
mov    %ax,-0x22(%rbp)
movzwl -0x2(%rbp),%eax
xor    $0xffffffff,%eax
and    $0xffff,%eax
mov    %eax,-0x28(%rbp)
cmpw   $0x0,-0x12(%rbp)
je     1185 <checksum_update+0x85>
mov    -0x10(%rbp),%rax
mov    %rax,%rcx
add    $0x2,%rcx
mov    %rcx,-0x10(%rbp)
movzwl (%rax),%ecx
mov    -0x28(%rbp),%eax
sub    %ecx,%eax
mov    %eax,-0x28(%rbp)
mov    -0x28(%rbp),%eax
and    $0x80000000,%eax
cmp    $0x0,%eax
je     1175 <checksum_update+0x75>
mov    -0x28(%rbp),%eax
add    $0xffffffff,%eax
mov    %eax,-0x28(%rbp)
mov    -0x28(%rbp),%eax
and    $0xffff,%eax
mov    %eax,-0x28(%rbp)
movswl -0x12(%rbp),%eax
sub    $0x2,%eax
mov    %ax,-0x12(%rbp)
jmp    112b <checksum_update+0x2b>
jmp    118a <checksum_update+0x8a>
cmpw   $0x0,-0x22(%rbp)
je     11e2 <checksum_update+0xe2>
mov    -0x20(%rbp),%rax
mov    %rax,%rcx
add    $0x2,%rcx
mov    %rcx,-0x20(%rbp)
movzwl (%rax),%eax
add    -0x28(%rbp),%eax
mov    %eax,-0x28(%rbp)
mov    -0x28(%rbp),%eax
and    $0x10000,%eax
cmp    $0x0,%eax
je     11d2 <checksum_update+0xd2>
mov    -0x28(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x28(%rbp)
mov    -0x28(%rbp),%eax
and    $0xffff,%eax
mov    %eax,-0x28(%rbp)
movswl -0x22(%rbp),%eax
sub    $0x2,%eax
mov    %ax,-0x22(%rbp)
jmp    118a <checksum_update+0x8a>
mov    -0x28(%rbp),%eax
xor    $0xffffffff,%eax
and    $0xffff,%eax
movzwl %ax,%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<checksum_update>:
xor    $0xffff,%edi
test   %dx,%dx
je     1145 <checksum_update+0x45>
movzwl %dx,%r9d
xor    %edx,%edx
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax,%rax,1)
movzwl (%rsi,%rdx,1),%eax
sub    %eax,%edi
lea    -0x1(%rdi),%eax
test   %edi,%edi
movzwl %ax,%eax
cmovns %edi,%eax
add    $0x2,%rdx
mov    %eax,%edi
cmp    %dx,%r9w
jne    1120 <checksum_update+0x20>
test   %r8w,%r8w
jne    114d <checksum_update+0x4d>
jmp    1181 <checksum_update+0x81>
mov    %edi,%eax
test   %r8w,%r8w
je     1181 <checksum_update+0x81>
movzwl %r8w,%r8d
xor    %esi,%esi
cs nopw 0x0(%rax,%rax,1)
nopl   (%rax)
movzwl (%rcx,%rsi,1),%edi
lea    (%rax,%rdi,1),%edx
test   $0x10000,%edx
lea    0x1(%rax,%rdi,1),%eax
movzwl %ax,%eax
cmove  %edx,%eax
add    $0x2,%rsi
cmp    %si,%r8w
jne    1160 <checksum_update+0x60>
not    %eax
ret

LLVM IR (-O0):
define zeroext i16 @checksum_update(i16 zeroext %0, i16* %1, i16 signext %2, i16* %3, i16 signext %4) {
%6 = alloca i16
%7 = alloca i16*
%8 = alloca i16
%9 = alloca i16*
%10 = alloca i16
%11 = alloca i32
store i16 %0, i16* %6
store i16* %1, i16** %7
store i16 %2, i16* %8
store i16* %3, i16** %9
store i16 %4, i16* %10
%12 = load i16, i16* %6
%13 = zext i16 %12 to i32
%14 = xor i32 %13, -1
%15 = and i32 %14, 65535
store i32 %15, i32* %11
br label %16
16: ; preds = %34, %5
%17 = load i16, i16* %8
%18 = icmp ne i16 %17, 0
br i1 %18, label %19, label %39
19: ; preds = %16
%20 = load i16*, i16** %7
%21 = getelementptr inbounds i16, i16* %20, i32 1
store i16* %21, i16** %7
%22 = load i16, i16* %20
%23 = zext i16 %22 to i32
%24 = load i32, i32* %11
%25 = sub i32 %24, %23
store i32 %25, i32* %11
%26 = load i32, i32* %11
%27 = and i32 %26, -2147483648
%28 = icmp ne i32 %27, 0
br i1 %28, label %29, label %34
29: ; preds = %19
%30 = load i32, i32* %11
%31 = add i32 %30, -1
store i32 %31, i32* %11
%32 = load i32, i32* %11
%33 = and i32 %32, 65535
store i32 %33, i32* %11
br label %34
34: ; preds = %29, %19
%35 = load i16, i16* %8
%36 = sext i16 %35 to i32
%37 = sub nsw i32 %36, 2
%38 = trunc i32 %37 to i16
store i16 %38, i16* %8
br label %16
39: ; preds = %16
br label %40
40: ; preds = %58, %39
%41 = load i16, i16* %10
%42 = icmp ne i16 %41, 0
br i1 %42, label %43, label %63
43: ; preds = %40
%44 = load i16*, i16** %9
%45 = getelementptr inbounds i16, i16* %44, i32 1
store i16* %45, i16** %9
%46 = load i16, i16* %44
%47 = zext i16 %46 to i32
%48 = load i32, i32* %11
%49 = add i32 %48, %47
store i32 %49, i32* %11
%50 = load i32, i32* %11
%51 = and i32 %50, 65536
%52 = icmp ne i32 %51, 0
br i1 %52, label %53, label %58
53: ; preds = %43
%54 = load i32, i32* %11
%55 = add i32 %54, 1
store i32 %55, i32* %11
%56 = load i32, i32* %11
%57 = and i32 %56, 65535
store i32 %57, i32* %11
br label %58
58: ; preds = %53, %43
%59 = load i16, i16* %10
%60 = sext i16 %59 to i32
%61 = sub nsw i32 %60, 2
%62 = trunc i32 %61 to i16
store i16 %62, i16* %10
br label %40
63: ; preds = %40
%64 = load i32, i32* %11
%65 = xor i32 %64, -1
%66 = and i32 %65, 65535
%67 = trunc i32 %66 to i16
ret i16 %67
}

LLVM IR (-O2):
define zeroext i16 @checksum_update(i16 zeroext %0, i16* nocapture %1, i16 signext %2, i16* nocapture %3, i16 signext %4) {
%6 = xor i16 %0, -1
%7 = zext i16 %6 to i32
%8 = icmp eq i16 %2, 0
br i1 %8, label %9, label %12
9: ; preds = %12, %5
%10 = phi i32 [ %7, %5 ], [ %23, %12 ]
%11 = icmp eq i16 %4, 0
br i1 %11, label %41, label %26
12: ; preds = %5, %12
%13 = phi i32 [ %23, %12 ], [ %7, %5 ]
%14 = phi i16 [ %24, %12 ], [ %2, %5 ]
%15 = phi i16* [ %16, %12 ], [ %1, %5 ]
%16 = getelementptr inbounds i16, i16* %15, i64 1
%17 = load i16, i16* %15
%18 = zext i16 %17 to i32
%19 = sub i32 %13, %18
%20 = icmp sgt i32 %19, -1
%21 = add i32 %19, 65535
%22 = and i32 %21, 65535
%23 = select i1 %20, i32 %19, i32 %22
%24 = add i16 %14, -2
%25 = icmp eq i16 %24, 0
br i1 %25, label %9, label %12
26: ; preds = %9, %26
%27 = phi i32 [ %38, %26 ], [ %10, %9 ]
%28 = phi i16 [ %39, %26 ], [ %4, %9 ]
%29 = phi i16* [ %30, %26 ], [ %3, %9 ]
%30 = getelementptr inbounds i16, i16* %29, i64 1
%31 = load i16, i16* %29
%32 = zext i16 %31 to i32
%33 = add i32 %27, %32
%34 = and i32 %33, 65536
%35 = icmp eq i32 %34, 0
%36 = add i32 %33, 1
%37 = and i32 %36, 65535
%38 = select i1 %35, i32 %33, i32 %37
%39 = add i16 %28, -2
%40 = icmp eq i16 %39, 0
br i1 %40, label %41, label %26
41: ; preds = %26, %9
%42 = phi i32 [ %10, %9 ], [ %38, %26 ]
%43 = trunc i32 %42 to i16
%44 = xor i16 %43, -1
ret i16 %44
}