#define NULL ((void *)0)
typedef unsigned long size_t; // Customize by platform.
typedef long intptr_t;
typedef unsigned long uintptr_t;
typedef long scalar_t__; // Either arithmetic or pointer type.
/* By default, we understand bool (as a convenience). */
typedef int bool;
#define false 0
#define true 1

/* Forward declarations */

/* Type definitions */
typedef int uint32_t;
struct tcphdr {
  int dummy;
};
struct iphdr {
  int ihl;
  scalar_t__ protocol;
};
struct ethhdr {
  int dummy;
};
struct __sk_buff {
  scalar_t__ data;
  scalar_t__ data_end;
};

/* Variables and functions */
scalar_t__ IPPROTO_TCP;
int TC_ACT_OK;
int TC_ACT_SHOT;
int handle_tcp(struct __sk_buff *, struct tcphdr *);
int handle_ipv4(struct __sk_buff *skb) {
  void *data_end = (void *)(long)skb->data_end;
  void *data = (void *)(long)skb->data;
  struct iphdr *iph;
  uint32_t ihl;
  if (data + sizeof(struct ethhdr) > data_end)
    return TC_ACT_SHOT;
  iph = (struct iphdr *)(data + sizeof(struct ethhdr));
  if ((void *)(iph + 1) > data_end)
    return TC_ACT_SHOT;
  ihl = iph->ihl * 4;
  if (((void *)iph) + ihl > data_end)
    return TC_ACT_SHOT;
  if (iph->protocol == IPPROTO_TCP)
    return handle_tcp(skb, (struct tcphdr *)(((void *)iph) + ihl));
  return TC_ACT_OK;
}


x86 assembly (clang, -O0):
<handle_ipv4>:
push   %rbp
mov    %rsp,%rbp
sub    $0x30,%rsp
mov    %rdi,-0x10(%rbp)
mov    -0x10(%rbp),%rax
mov    0x8(%rax),%rax
mov    %rax,-0x18(%rbp)
mov    -0x10(%rbp),%rax
mov    (%rax),%rax
mov    %rax,-0x20(%rbp)
mov    -0x20(%rbp),%rax
add    $0x4,%rax
cmp    -0x18(%rbp),%rax
jbe    1156 <handle_ipv4+0x46>
mov    0x2e9c(%rip),%rax
mov    (%rax),%eax
mov    %eax,-0x4(%rbp)
jmp    11f7 <handle_ipv4+0xe7>
mov    -0x20(%rbp),%rax
add    $0x4,%rax
mov    %rax,-0x28(%rbp)
mov    -0x28(%rbp),%rax
add    $0x10,%rax
cmp    -0x18(%rbp),%rax
jbe    1185 <handle_ipv4+0x75>
mov    0x2e6d(%rip),%rax
mov    (%rax),%eax
mov    %eax,-0x4(%rbp)
jmp    11f7 <handle_ipv4+0xe7>
mov    -0x28(%rbp),%rax
mov    (%rax),%eax
shl    $0x2,%eax
mov    %eax,-0x2c(%rbp)
mov    -0x28(%rbp),%rax
movslq -0x2c(%rbp),%rcx
add    %rcx,%rax
cmp    -0x18(%rbp),%rax
jbe    11b7 <handle_ipv4+0xa7>
mov    0x2e3b(%rip),%rax
mov    (%rax),%eax
mov    %eax,-0x4(%rbp)
jmp    11f7 <handle_ipv4+0xe7>
mov    -0x28(%rbp),%rax
mov    0x8(%rax),%rax
mov    0x2e1a(%rip),%rcx
cmp    (%rcx),%rax
jne    11eb <handle_ipv4+0xdb>
mov    -0x10(%rbp),%rdi
mov    -0x28(%rbp),%rsi
movslq -0x2c(%rbp),%rax
add    %rax,%rsi
call   1030 <handle_tcp@plt>
mov    %eax,-0x4(%rbp)
jmp    11f7 <handle_ipv4+0xe7>
mov    0x2de6(%rip),%rax
mov    (%rax),%eax
mov    %eax,-0x4(%rbp)
mov    -0x4(%rbp),%eax
add    $0x30,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<handle_ipv4>:
mov    (%rdi),%rax
mov    0x8(%rdi),%rcx
lea    0x4(%rax),%rdx
cmp    %rcx,%rdx
ja     1135 <handle_ipv4+0x25>
lea    0x14(%rax),%rsi
cmp    %rcx,%rsi
ja     1135 <handle_ipv4+0x25>
movslq (%rdx),%rsi
lea    (%rdx,%rsi,4),%rsi
cmp    %rcx,%rsi
jbe    113f <handle_ipv4+0x2f>
mov    0x2eac(%rip),%rax
mov    (%rax),%eax
ret
mov    0xc(%rax),%rax
mov    0x2e96(%rip),%rcx
cmp    (%rcx),%rax
jne    1154 <handle_ipv4+0x44>
jmp    1030 <handle_tcp@plt>
mov    0x2e7d(%rip),%rax
mov    (%rax),%eax
ret

LLVM IR (-O0):
%struct.__sk_buff = type { i64, i64 }
%struct.iphdr = type { i32, i64 }
%struct.tcphdr = type { i32 }
@TC_ACT_SHOT = global i32 0
@IPPROTO_TCP = global i64 0
@TC_ACT_OK = global i32 0
define i32 @handle_ipv4(%struct.__sk_buff* %0) {
%2 = alloca i32
%3 = alloca %struct.__sk_buff*
%4 = alloca i8*
%5 = alloca i8*
%6 = alloca %struct.iphdr*
%7 = alloca i32
store %struct.__sk_buff* %0, %struct.__sk_buff** %3
%8 = load %struct.__sk_buff*, %struct.__sk_buff** %3
%9 = getelementptr inbounds %struct.__sk_buff, %struct.__sk_buff* %8, i32 0, i32 1
%10 = load i64, i64* %9
%11 = inttoptr i64 %10 to i8*
store i8* %11, i8** %4
%12 = load %struct.__sk_buff*, %struct.__sk_buff** %3
%13 = getelementptr inbounds %struct.__sk_buff, %struct.__sk_buff* %12, i32 0, i32 0
%14 = load i64, i64* %13
%15 = inttoptr i64 %14 to i8*
store i8* %15, i8** %5
%16 = load i8*, i8** %5
%17 = getelementptr i8, i8* %16, i64 4
%18 = load i8*, i8** %4
%19 = icmp ugt i8* %17, %18
br i1 %19, label %20, label %22
20: ; preds = %1
%21 = load i32, i32* @TC_ACT_SHOT
store i32 %21, i32* %2
br label %64
22: ; preds = %1
%23 = load i8*, i8** %5
%24 = getelementptr i8, i8* %23, i64 4
%25 = bitcast i8* %24 to %struct.iphdr*
store %struct.iphdr* %25, %struct.iphdr** %6
%26 = load %struct.iphdr*, %struct.iphdr** %6
%27 = getelementptr inbounds %struct.iphdr, %struct.iphdr* %26, i64 1
%28 = bitcast %struct.iphdr* %27 to i8*
%29 = load i8*, i8** %4
%30 = icmp ugt i8* %28, %29
br i1 %30, label %31, label %33
31: ; preds = %22
%32 = load i32, i32* @TC_ACT_SHOT
store i32 %32, i32* %2
br label %64
33: ; preds = %22
%34 = load %struct.iphdr*, %struct.iphdr** %6
%35 = getelementptr inbounds %struct.iphdr, %struct.iphdr* %34, i32 0, i32 0
%36 = load i32, i32* %35
%37 = mul nsw i32 %36, 4
store i32 %37, i32* %7
%38 = load %struct.iphdr*, %struct.iphdr** %6
%39 = bitcast %struct.iphdr* %38 to i8*
%40 = load i32, i32* %7
%41 = sext i32 %40 to i64
%42 = getelementptr i8, i8* %39, i64 %41
%43 = load i8*, i8** %4
%44 = icmp ugt i8* %42, %43
br i1 %44, label %45, label %47
45: ; preds = %33
%46 = load i32, i32* @TC_ACT_SHOT
store i32 %46, i32* %2
br label %64
47: ; preds = %33
%48 = load %struct.iphdr*, %struct.iphdr** %6
%49 = getelementptr inbounds %struct.iphdr, %struct.iphdr* %48, i32 0, i32 1
%50 = load i64, i64* %49
%51 = load i64, i64* @IPPROTO_TCP
%52 = icmp eq i64 %50, %51
br i1 %52, label %53, label %62
53: ; preds = %47
%54 = load %struct.__sk_buff*, %struct.__sk_buff** %3
%55 = load %struct.iphdr*, %struct.iphdr** %6
%56 = bitcast %struct.iphdr* %55 to i8*
%57 = load i32, i32* %7
%58 = sext i32 %57 to i64
%59 = getelementptr i8, i8* %56, i64 %58
%60 = bitcast i8* %59 to %struct.tcphdr*
%61 = call i32 @handle_tcp(%struct.__sk_buff* %54, %struct.tcphdr* %60)
store i32 %61, i32* %2
br label %64
62: ; preds = %47
%63 = load i32, i32* @TC_ACT_OK
store i32 %63, i32* %2
br label %64
64: ; preds = %62, %53, %45, %31, %20
%65 = load i32, i32* %2
ret i32 %65
}

LLVM IR (-O2):
%struct.__sk_buff = type { i64, i64 }
%struct.tcphdr = type { i32 }
@TC_ACT_SHOT = global i32 0
@IPPROTO_TCP = global i64 0
@TC_ACT_OK = global i32 0
define i32 @handle_ipv4(%struct.__sk_buff* %0) {
%2 = getelementptr inbounds %struct.__sk_buff, %struct.__sk_buff* %0, i64 0, i32 1
%3 = load i64, i64* %2
%4 = inttoptr i64 %3 to i8*
%5 = getelementptr inbounds %struct.__sk_buff, %struct.__sk_buff* %0, i64 0, i32 0
%6 = load i64, i64* %5
%7 = inttoptr i64 %6 to i8*
%8 = getelementptr i8, i8* %7, i64 4
%9 = icmp ugt i8* %8, %4
br i1 %9, label %10, label %12
10: ; preds = %1
%11 = load i32, i32* @TC_ACT_SHOT
br label %37
12: ; preds = %1
%13 = getelementptr i8, i8* %7, i64 20
%14 = icmp ugt i8* %13, %4
br i1 %14, label %15, label %17
15: ; preds = %12
%16 = load i32, i32* @TC_ACT_SHOT
br label %37
17: ; preds = %12
%18 = bitcast i8* %8 to i32*
%19 = load i32, i32* %18
%20 = shl nsw i32 %19, 2
%21 = sext i32 %20 to i64
%22 = getelementptr i8, i8* %8, i64 %21
%23 = icmp ugt i8* %22, %4
br i1 %23, label %24, label %26
24: ; preds = %17
%25 = load i32, i32* @TC_ACT_SHOT
br label %37
26: ; preds = %17
%27 = getelementptr i8, i8* %7, i64 12
%28 = bitcast i8* %27 to i64*
%29 = load i64, i64* %28
%30 = load i64, i64* @IPPROTO_TCP
%31 = icmp eq i64 %29, %30
br i1 %31, label %32, label %35
32: ; preds = %26
%33 = bitcast i8* %22 to %struct.tcphdr*
%34 = tail call i32 @handle_tcp(%struct.__sk_buff* %0, %struct.tcphdr* %33)
br label %37
35: ; preds = %26
%36 = load i32, i32* @TC_ACT_OK
br label %37
37: ; preds = %35, %32, %24, %15, %10
%38 = phi i32 [ %11, %10 ], [ %16, %15 ], [ %25, %24 ], [ %34, %32 ], [ %36, %35 ]
ret i32 %38
}