unsigned short ip_hdr_csum(unsigned int *ip, int len) {
  unsigned int sum = 0;
  int i;
  unsigned short *sp = (unsigned short *)ip;
  if (len == 5) {
    sum = sp[0] + sp[1] + sp[2] + sp[3] + sp[4] + sp[5] + sp[6] + sp[7] +
          sp[8] + sp[9];
  } else {
    for (i = 0; i < 2 * len; i++)
      sum += sp[i];
  }
  sum = (sum & 0xFFFF) + (sum >> 16);
  sum = (sum & 0xFFFF) + (sum >> 16);
  return ~sum;
}


x86 assembly (clang, -O0):
<ip_hdr_csum>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %esi,-0xc(%rbp)
movl   $0x0,-0x10(%rbp)
mov    -0x8(%rbp),%rax
mov    %rax,-0x20(%rbp)
cmpl   $0x5,-0xc(%rbp)
jne    118d <ip_hdr_csum+0x8d>
mov    -0x20(%rbp),%rax
movzwl (%rax),%eax
mov    -0x20(%rbp),%rcx
movzwl 0x2(%rcx),%ecx
add    %ecx,%eax
mov    -0x20(%rbp),%rcx
movzwl 0x4(%rcx),%ecx
add    %ecx,%eax
mov    -0x20(%rbp),%rcx
movzwl 0x6(%rcx),%ecx
add    %ecx,%eax
mov    -0x20(%rbp),%rcx
movzwl 0x8(%rcx),%ecx
add    %ecx,%eax
mov    -0x20(%rbp),%rcx
movzwl 0xa(%rcx),%ecx
add    %ecx,%eax
mov    -0x20(%rbp),%rcx
movzwl 0xc(%rcx),%ecx
add    %ecx,%eax
mov    -0x20(%rbp),%rcx
movzwl 0xe(%rcx),%ecx
add    %ecx,%eax
mov    -0x20(%rbp),%rcx
movzwl 0x10(%rcx),%ecx
add    %ecx,%eax
mov    -0x20(%rbp),%rcx
movzwl 0x12(%rcx),%ecx
add    %ecx,%eax
mov    %eax,-0x10(%rbp)
jmp    11ca <ip_hdr_csum+0xca>
movl   $0x0,-0x14(%rbp)
mov    -0x14(%rbp),%eax
mov    -0xc(%rbp),%ecx
shl    $0x1,%ecx
cmp    %ecx,%eax
jge    11c5 <ip_hdr_csum+0xc5>
mov    -0x20(%rbp),%rax
movslq -0x14(%rbp),%rcx
movzwl (%rax,%rcx,2),%eax
add    -0x10(%rbp),%eax
mov    %eax,-0x10(%rbp)
mov    -0x14(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x14(%rbp)
jmp    1194 <ip_hdr_csum+0x94>
jmp    11ca <ip_hdr_csum+0xca>
mov    -0x10(%rbp),%eax
and    $0xffff,%eax
mov    -0x10(%rbp),%ecx
shr    $0x10,%ecx
add    %ecx,%eax
mov    %eax,-0x10(%rbp)
mov    -0x10(%rbp),%eax
and    $0xffff,%eax
mov    -0x10(%rbp),%ecx
shr    $0x10,%ecx
add    %ecx,%eax
mov    %eax,-0x10(%rbp)
mov    -0x10(%rbp),%eax
xor    $0xffffffff,%eax
movzwl %ax,%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<ip_hdr_csum>:
cmp    $0x5,%esi
jne    1144 <ip_hdr_csum+0x44>
movdqu (%rdi),%xmm0
pxor   %xmm1,%xmm1
movdqa %xmm0,%xmm2
punpckhwd %xmm1,%xmm2
punpcklwd %xmm1,%xmm0
paddd  %xmm2,%xmm0
movzwl 0x10(%rdi),%eax
movzwl 0x12(%rdi),%ecx
pshufd $0xee,%xmm0,%xmm1
paddd  %xmm0,%xmm1
pshufd $0x55,%xmm1,%xmm0
paddd  %xmm1,%xmm0
movd   %xmm0,%edx
add    %eax,%edx
add    %ecx,%edx
jmp    123f <ip_hdr_csum+0x13f>
test   %esi,%esi
jle    1163 <ip_hdr_csum+0x63>
add    %esi,%esi
cmp    $0x2,%esi
mov    $0x1,%eax
cmovge %esi,%eax
cmp    $0x8,%eax
jae    116a <ip_hdr_csum+0x6a>
xor    %ecx,%ecx
xor    %edx,%edx
jmp    1230 <ip_hdr_csum+0x130>
xor    %edx,%edx
jmp    123f <ip_hdr_csum+0x13f>
mov    %eax,%ecx
and    $0x7ffffff8,%ecx
lea    -0x8(%rcx),%rdx
mov    %rdx,%r8
shr    $0x3,%r8
add    $0x1,%r8
test   %rdx,%rdx
je     1251 <ip_hdr_csum+0x151>
mov    %r8,%rdx
and    $0xfffffffffffffffe,%rdx
pxor   %xmm2,%xmm2
xor    %esi,%esi
pxor   %xmm0,%xmm0
pxor   %xmm1,%xmm1
nop
movq   (%rdi,%rsi,2),%xmm3
movq   0x8(%rdi,%rsi,2),%xmm4
punpcklwd %xmm2,%xmm3
paddd  %xmm0,%xmm3
punpcklwd %xmm2,%xmm4
paddd  %xmm1,%xmm4
movq   0x10(%rdi,%rsi,2),%xmm0
movq   0x18(%rdi,%rsi,2),%xmm1
punpcklwd %xmm2,%xmm0
paddd  %xmm3,%xmm0
punpcklwd %xmm2,%xmm1
paddd  %xmm4,%xmm1
add    $0x10,%rsi
add    $0xfffffffffffffffe,%rdx
jne    11a0 <ip_hdr_csum+0xa0>
test   $0x1,%r8b
je     1206 <ip_hdr_csum+0x106>
movq   (%rdi,%rsi,2),%xmm2
movq   0x8(%rdi,%rsi,2),%xmm3
pxor   %xmm4,%xmm4
punpcklwd %xmm4,%xmm2
paddd  %xmm2,%xmm0
punpcklwd %xmm4,%xmm3
paddd  %xmm3,%xmm1
paddd  %xmm1,%xmm0
pshufd $0xee,%xmm0,%xmm1
paddd  %xmm0,%xmm1
pshufd $0x55,%xmm1,%xmm0
paddd  %xmm1,%xmm0
movd   %xmm0,%edx
cmp    %rax,%rcx
je     123f <ip_hdr_csum+0x13f>
cs nopw 0x0(%rax,%rax,1)
nop
movzwl (%rdi,%rcx,2),%esi
add    %esi,%edx
add    $0x1,%rcx
cmp    %rcx,%rax
jne    1230 <ip_hdr_csum+0x130>
movzwl %dx,%eax
shr    $0x10,%edx
add    %eax,%edx
mov    %edx,%eax
shr    $0x10,%eax
add    %edx,%eax
not    %eax
ret
pxor   %xmm0,%xmm0
xor    %esi,%esi
pxor   %xmm1,%xmm1
test   $0x1,%r8b
jne    11e7 <ip_hdr_csum+0xe7>
jmp    1206 <ip_hdr_csum+0x106>

LLVM IR (-O0):
define zeroext i16 @ip_hdr_csum(i32* %0, i32 %1) {
%3 = alloca i32*
%4 = alloca i32
%5 = alloca i32
%6 = alloca i32
%7 = alloca i16*
store i32* %0, i32** %3
store i32 %1, i32* %4
store i32 0, i32* %5
%8 = load i32*, i32** %3
%9 = bitcast i32* %8 to i16*
store i16* %9, i16** %7
%10 = load i32, i32* %4
%11 = icmp eq i32 %10, 5
br i1 %11, label %12, label %62
12: ; preds = %2
%13 = load i16*, i16** %7
%14 = getelementptr inbounds i16, i16* %13, i64 0
%15 = load i16, i16* %14
%16 = zext i16 %15 to i32
%17 = load i16*, i16** %7
%18 = getelementptr inbounds i16, i16* %17, i64 1
%19 = load i16, i16* %18
%20 = zext i16 %19 to i32
%21 = add nsw i32 %16, %20
%22 = load i16*, i16** %7
%23 = getelementptr inbounds i16, i16* %22, i64 2
%24 = load i16, i16* %23
%25 = zext i16 %24 to i32
%26 = add nsw i32 %21, %25
%27 = load i16*, i16** %7
%28 = getelementptr inbounds i16, i16* %27, i64 3
%29 = load i16, i16* %28
%30 = zext i16 %29 to i32
%31 = add nsw i32 %26, %30
%32 = load i16*, i16** %7
%33 = getelementptr inbounds i16, i16* %32, i64 4
%34 = load i16, i16* %33
%35 = zext i16 %34 to i32
%36 = add nsw i32 %31, %35
%37 = load i16*, i16** %7
%38 = getelementptr inbounds i16, i16* %37, i64 5
%39 = load i16, i16* %38
%40 = zext i16 %39 to i32
%41 = add nsw i32 %36, %40
%42 = load i16*, i16** %7
%43 = getelementptr inbounds i16, i16* %42, i64 6
%44 = load i16, i16* %43
%45 = zext i16 %44 to i32
%46 = add nsw i32 %41, %45
%47 = load i16*, i16** %7
%48 = getelementptr inbounds i16, i16* %47, i64 7
%49 = load i16, i16* %48
%50 = zext i16 %49 to i32
%51 = add nsw i32 %46, %50
%52 = load i16*, i16** %7
%53 = getelementptr inbounds i16, i16* %52, i64 8
%54 = load i16, i16* %53
%55 = zext i16 %54 to i32
%56 = add nsw i32 %51, %55
%57 = load i16*, i16** %7
%58 = getelementptr inbounds i16, i16* %57, i64 9
%59 = load i16, i16* %58
%60 = zext i16 %59 to i32
%61 = add nsw i32 %56, %60
store i32 %61, i32* %5
br label %81
62: ; preds = %2
store i32 0, i32* %6
br label %63
63: ; preds = %77, %62
%64 = load i32, i32* %6
%65 = load i32, i32* %4
%66 = mul nsw i32 2, %65
%67 = icmp slt i32 %64, %66
br i1 %67, label %68, label %80
68: ; preds = %63
%69 = load i16*, i16** %7
%70 = load i32, i32* %6
%71 = sext i32 %70 to i64
%72 = getelementptr inbounds i16, i16* %69, i64 %71
%73 = load i16, i16* %72
%74 = zext i16 %73 to i32
%75 = load i32, i32* %5
%76 = add i32 %75, %74
store i32 %76, i32* %5
br label %77
77: ; preds = %68
%78 = load i32, i32* %6
%79 = add nsw i32 %78, 1
store i32 %79, i32* %6
br label %63
80: ; preds = %63
br label %81
81: ; preds = %80, %12
%82 = load i32, i32* %5
%83 = and i32 %82, 65535
%84 = load i32, i32* %5
%85 = lshr i32 %84, 16
%86 = add i32 %83, %85
store i32 %86, i32* %5
%87 = load i32, i32* %5
%88 = and i32 %87, 65535
%89 = load i32, i32* %5
%90 = lshr i32 %89, 16
%91 = add i32 %88, %90
store i32 %91, i32* %5
%92 = load i32, i32* %5
%93 = xor i32 %92, -1
%94 = trunc i32 %93 to i16
ret i16 %94
}

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