int ip_checksum(unsigned short *q) {
  int iphl = ((*q) & 0x0F00) >> 7;
  int x = iphl << 1;
  unsigned short *uph = q;
  unsigned long sum = 0;
  unsigned short checksum;
  q[5] = 0;
  while (iphl--)
    sum += *uph++;
  checksum = sum;
  while (sum >>= 16) {
    sum += checksum;
    checksum = sum;
  }
  q[5] = checksum ^ 0xFFFF;
  return x;
}


x86 assembly (clang, -O0):
<ip_checksum>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    -0x8(%rbp),%rax
movzwl (%rax),%eax
and    $0xf00,%eax
sar    $0x7,%eax
mov    %eax,-0xc(%rbp)
mov    -0xc(%rbp),%eax
shl    $0x1,%eax
mov    %eax,-0x10(%rbp)
mov    -0x8(%rbp),%rax
mov    %rax,-0x18(%rbp)
movq   $0x0,-0x20(%rbp)
mov    -0x8(%rbp),%rax
movw   $0x0,0xa(%rax)
mov    -0xc(%rbp),%eax
mov    %eax,%ecx
add    $0xffffffff,%ecx
mov    %ecx,-0xc(%rbp)
cmp    $0x0,%eax
je     1170 <ip_checksum+0x70>
mov    -0x18(%rbp),%rax
mov    %rax,%rcx
add    $0x2,%rcx
mov    %rcx,-0x18(%rbp)
movzwl (%rax),%eax
add    -0x20(%rbp),%rax
mov    %rax,-0x20(%rbp)
jmp    113d <ip_checksum+0x3d>
mov    -0x20(%rbp),%rax
mov    %ax,-0x22(%rbp)
mov    -0x20(%rbp),%rax
shr    $0x10,%rax
mov    %rax,-0x20(%rbp)
cmp    $0x0,%rax
je     11a7 <ip_checksum+0xa7>
movzwl -0x22(%rbp),%eax
add    -0x20(%rbp),%rax
mov    %rax,-0x20(%rbp)
mov    -0x20(%rbp),%rax
mov    %ax,-0x22(%rbp)
jmp    1178 <ip_checksum+0x78>
movzwl -0x22(%rbp),%eax
xor    $0xffff,%eax
mov    %ax,%cx
mov    -0x8(%rbp),%rax
mov    %cx,0xa(%rax)
mov    -0x10(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<ip_checksum>:
movzwl (%rdi),%ecx
mov    %ecx,%eax
shr    $0x7,%eax
movw   $0x0,0xa(%rdi)
and    $0x1e,%eax
je     1248 <ip_checksum+0x148>
movzwl %cx,%edx
lea    -0x1(%rax),%r8d
lea    0x2(%rdi),%r11
lea    -0x2(%rax),%r9d
cmp    $0x3,%r9d
jbe    120a <ip_checksum+0x10a>
and    $0xfffffffc,%r9d
movd   %edx,%xmm0
lea    -0x4(%r9),%rcx
mov    %rcx,%r10
shr    $0x2,%r10
add    $0x1,%r10
test   %rcx,%rcx
je     1253 <ip_checksum+0x153>
mov    %r10,%rdx
and    $0xfffffffffffffffe,%rdx
pxor   %xmm2,%xmm2
xor    %esi,%esi
pxor   %xmm1,%xmm1
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax,%rax,1)
movd   0x2(%rdi,%rsi,2),%xmm3
movd   0x6(%rdi,%rsi,2),%xmm4
punpcklwd %xmm2,%xmm3
punpckldq %xmm2,%xmm3
paddq  %xmm0,%xmm3
punpcklwd %xmm2,%xmm4
punpckldq %xmm2,%xmm4
paddq  %xmm1,%xmm4
movd   0xa(%rdi,%rsi,2),%xmm0
movd   0xe(%rdi,%rsi,2),%xmm1
punpcklwd %xmm2,%xmm0
punpckldq %xmm2,%xmm0
paddq  %xmm3,%xmm0
punpcklwd %xmm2,%xmm1
punpckldq %xmm2,%xmm1
paddq  %xmm4,%xmm1
add    $0x8,%rsi
add    $0xfffffffffffffffe,%rdx
jne    1170 <ip_checksum+0x70>
test   $0x1,%r10b
je     11f1 <ip_checksum+0xf1>
movd   (%r11,%rsi,2),%xmm2
movd   0x4(%r11,%rsi,2),%xmm3
pxor   %xmm4,%xmm4
punpcklwd %xmm4,%xmm2
punpckldq %xmm4,%xmm2
paddq  %xmm2,%xmm0
punpcklwd %xmm4,%xmm3
punpckldq %xmm4,%xmm3
paddq  %xmm3,%xmm1
paddq  %xmm1,%xmm0
lea    (%r11,%r9,2),%r11
sub    %r9d,%r8d
pshufd $0xee,%xmm0,%xmm1
paddq  %xmm0,%xmm1
movq   %xmm1,%rdx
mov    %r8d,%r8d
xor    %ecx,%ecx
nop
movzwl (%r11,%rcx,2),%esi
add    %rsi,%rdx
add    $0x1,%rcx
cmp    %ecx,%r8d
jne    1210 <ip_checksum+0x110>
cmp    $0x10000,%rdx
jb     124a <ip_checksum+0x14a>
nopw   0x0(%rax,%rax,1)
mov    %rdx,%rcx
shr    $0x10,%rcx
movzwl %dx,%edx
add    %rcx,%rdx
cmp    $0xffff,%rdx
ja     1230 <ip_checksum+0x130>
jmp    124a <ip_checksum+0x14a>
xor    %edx,%edx
add    %eax,%eax
not    %edx
mov    %dx,0xa(%rdi)
ret
pxor   %xmm1,%xmm1
xor    %esi,%esi
test   $0x1,%r10b
jne    11c8 <ip_checksum+0xc8>
jmp    11f1 <ip_checksum+0xf1>

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

LLVM IR (-O2):
define i32 @ip_checksum(i16* nocapture %0) {
%2 = load i16, i16* %0
%3 = lshr i16 %2, 7
%4 = and i16 %3, 30
%5 = zext i16 %4 to i32
%6 = getelementptr inbounds i16, i16* %0, i64 5
store i16 0, i16* %6
%7 = icmp eq i16 %4, 0
br i1 %7, label %101, label %8
8: ; preds = %1
%9 = add nsw i32 %5, -1
%10 = getelementptr inbounds i16, i16* %0, i64 1
%11 = zext i16 %2 to i64
%12 = add nsw i32 %5, -2
%13 = icmp ult i32 %12, 4
br i1 %13, label %14, label %18
14: ; preds = %78, %8
%15 = phi i64 [ %11, %8 ], [ %82, %78 ]
%16 = phi i16* [ %10, %8 ], [ %21, %78 ]
%17 = phi i32 [ %9, %8 ], [ %22, %78 ]
br label %85
18: ; preds = %8
%19 = and i32 %12, -4
%20 = zext i32 %19 to i64
%21 = getelementptr i16, i16* %10, i64 %20
%22 = sub nsw i32 %9, %19
%23 = insertelement <2 x i64> <i64 poison, i64 0>, i64 %11, i64 0
%24 = add nsw i64 %20, -4
%25 = lshr exact i64 %24, 2
%26 = add nuw nsw i64 %25, 1
%27 = and i64 %26, 1
%28 = icmp eq i64 %24, 0
br i1 %28, label %60, label %29
29: ; preds = %18
%30 = and i64 %26, 9223372036854775806
br label %31
31: ; preds = %31, %29
%32 = phi i64 [ 0, %29 ], [ %57, %31 ]
%33 = phi <2 x i64> [ %23, %29 ], [ %55, %31 ]
%34 = phi <2 x i64> [ zeroinitializer, %29 ], [ %56, %31 ]
%35 = phi i64 [ 0, %29 ], [ %58, %31 ]
%36 = getelementptr i16, i16* %10, i64 %32
%37 = bitcast i16* %36 to <2 x i16>*
%38 = load <2 x i16>, <2 x i16>* %37
%39 = getelementptr i16, i16* %36, i64 2
%40 = bitcast i16* %39 to <2 x i16>*
%41 = load <2 x i16>, <2 x i16>* %40
%42 = zext <2 x i16> %38 to <2 x i64>
%43 = zext <2 x i16> %41 to <2 x i64>
%44 = add <2 x i64> %33, %42
%45 = add <2 x i64> %34, %43
%46 = or i64 %32, 4
%47 = getelementptr i16, i16* %10, i64 %46
%48 = bitcast i16* %47 to <2 x i16>*
%49 = load <2 x i16>, <2 x i16>* %48
%50 = getelementptr i16, i16* %47, i64 2
%51 = bitcast i16* %50 to <2 x i16>*
%52 = load <2 x i16>, <2 x i16>* %51
%53 = zext <2 x i16> %49 to <2 x i64>
%54 = zext <2 x i16> %52 to <2 x i64>
%55 = add <2 x i64> %44, %53
%56 = add <2 x i64> %45, %54
%57 = add nuw i64 %32, 8
%58 = add i64 %35, 2
%59 = icmp eq i64 %58, %30
br i1 %59, label %60, label %31
60: ; preds = %31, %18
%61 = phi <2 x i64> [ undef, %18 ], [ %55, %31 ]
%62 = phi <2 x i64> [ undef, %18 ], [ %56, %31 ]
%63 = phi i64 [ 0, %18 ], [ %57, %31 ]
%64 = phi <2 x i64> [ %23, %18 ], [ %55, %31 ]
%65 = phi <2 x i64> [ zeroinitializer, %18 ], [ %56, %31 ]
%66 = icmp eq i64 %27, 0
br i1 %66, label %78, label %67
67: ; preds = %60
%68 = getelementptr i16, i16* %10, i64 %63
%69 = bitcast i16* %68 to <2 x i16>*
%70 = load <2 x i16>, <2 x i16>* %69
%71 = getelementptr i16, i16* %68, i64 2
%72 = bitcast i16* %71 to <2 x i16>*
%73 = load <2 x i16>, <2 x i16>* %72
%74 = zext <2 x i16> %70 to <2 x i64>
%75 = zext <2 x i16> %73 to <2 x i64>
%76 = add <2 x i64> %64, %74
%77 = add <2 x i64> %65, %75
br label %78
78: ; preds = %60, %67
%79 = phi <2 x i64> [ %61, %60 ], [ %76, %67 ]
%80 = phi <2 x i64> [ %62, %60 ], [ %77, %67 ]
%81 = add <2 x i64> %80, %79
%82 = call i64 @llvm.vector.reduce.add.v2i64(<2 x i64> %81)
br label %14
83: ; preds = %85
%84 = icmp ult i64 %93, 65536
br i1 %84, label %101, label %95
85: ; preds = %14, %85
%86 = phi i64 [ %93, %85 ], [ %15, %14 ]
%87 = phi i16* [ %91, %85 ], [ %16, %14 ]
%88 = phi i32 [ %90, %85 ], [ %17, %14 ]
%89 = load i16, i16* %87
%90 = add nsw i32 %88, -1
%91 = getelementptr inbounds i16, i16* %87, i64 1
%92 = zext i16 %89 to i64
%93 = add i64 %86, %92
%94 = icmp eq i32 %90, 0
br i1 %94, label %83, label %85
95: ; preds = %83, %95
%96 = phi i64 [ %99, %95 ], [ %93, %83 ]
%97 = lshr i64 %96, 16
%98 = and i64 %96, 65535
%99 = add nuw nsw i64 %97, %98
%100 = icmp ult i64 %99, 65536
br i1 %100, label %101, label %95
101: ; preds = %95, %1, %83
%102 = phi i64 [ %93, %83 ], [ 0, %1 ], [ %99, %95 ]
%103 = shl nuw nsw i32 %5, 1
%104 = trunc i64 %102 to i16
%105 = xor i16 %104, -1
store i16 %105, i16* %6
ret i32 %103
}