#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 */
struct pagetable {
  int dummy;
};

/* Variables and functions */
int /*<<< orphan*/ page_free(void *);
scalar_t__ pagetable_getmap(struct pagetable *, unsigned int, unsigned int *,
                            int *);
int /*<<< orphan*/ pagetable_unmap(struct pagetable *, unsigned int);
void pagetable_free(struct pagetable *p, unsigned vaddr, unsigned length) {
  unsigned npages = length / 4096;
  if (length % 4096)
    npages++;
  vaddr &= 0xfffff000;
  while (npages > 0) {
    unsigned paddr;
    int flags;
    if (pagetable_getmap(p, vaddr, &paddr, &flags)) {
      pagetable_unmap(p, vaddr);
      if (flags & 2)
        page_free((void *)paddr);
    }
    vaddr += 4096;
    npages--;
  }
}


x86 assembly (clang, -O0):
<pagetable_free>:
push   %rbp
mov    %rsp,%rbp
sub    $0x20,%rsp
mov    %rdi,-0x8(%rbp)
mov    %esi,-0xc(%rbp)
mov    %edx,-0x10(%rbp)
mov    -0x10(%rbp),%eax
shr    $0xc,%eax
mov    %eax,-0x14(%rbp)
mov    -0x10(%rbp),%eax
and    $0xfff,%eax
cmp    $0x0,%eax
je     1165 <pagetable_free+0x35>
mov    -0x14(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x14(%rbp)
mov    -0xc(%rbp),%eax
and    $0xfffff000,%eax
mov    %eax,-0xc(%rbp)
cmpl   $0x0,-0x14(%rbp)
jbe    11db <pagetable_free+0xab>
mov    -0x8(%rbp),%rdi
mov    -0xc(%rbp),%esi
lea    -0x18(%rbp),%rdx
lea    -0x1c(%rbp),%rcx
call   1030 <pagetable_getmap@plt>
cmp    $0x0,%rax
je     11c2 <pagetable_free+0x92>
mov    -0x8(%rbp),%rdi
mov    -0xc(%rbp),%esi
call   1050 <pagetable_unmap@plt>
mov    -0x1c(%rbp),%eax
and    $0x2,%eax
cmp    $0x0,%eax
je     11bd <pagetable_free+0x8d>
mov    -0x18(%rbp),%eax
mov    %eax,%edi
call   1040 <page_free@plt>
jmp    11c2 <pagetable_free+0x92>
mov    -0xc(%rbp),%eax
add    $0x1000,%eax
mov    %eax,-0xc(%rbp)
mov    -0x14(%rbp),%eax
add    $0xffffffff,%eax
mov    %eax,-0x14(%rbp)
jmp    1170 <pagetable_free+0x40>
add    $0x20,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<pagetable_free>:
push   %rbp
push   %r15
push   %r14
push   %r12
push   %rbx
sub    $0x10,%rsp
mov    %edx,%eax
shr    $0xc,%eax
xor    %ebp,%ebp
test   $0xfff,%edx
setne  %bpl
add    %eax,%ebp
je     11ac <pagetable_free+0x7c>
mov    %esi,%ebx
mov    %rdi,%r14
and    $0xfffff000,%ebx
lea    0xc(%rsp),%r15
lea    0x8(%rsp),%r12
jmp    117b <pagetable_free+0x4b>
nopl   0x0(%rax,%rax,1)
add    $0x1000,%ebx
add    $0xffffffff,%ebp
je     11ac <pagetable_free+0x7c>
mov    %r14,%rdi
mov    %ebx,%esi
mov    %r15,%rdx
mov    %r12,%rcx
call   1030 <pagetable_getmap@plt>
test   %rax,%rax
je     1170 <pagetable_free+0x40>
mov    %r14,%rdi
mov    %ebx,%esi
call   1050 <pagetable_unmap@plt>
testb  $0x2,0x8(%rsp)
je     1170 <pagetable_free+0x40>
mov    0xc(%rsp),%edi
call   1040 <page_free@plt>
jmp    1170 <pagetable_free+0x40>
add    $0x10,%rsp
pop    %rbx
pop    %r12
pop    %r14
pop    %r15
pop    %rbp
ret

LLVM IR (-O0):
%struct.pagetable = type { i32 }
define void @pagetable_free(%struct.pagetable* %0, i32 %1, i32 %2) {
%4 = alloca %struct.pagetable*
%5 = alloca i32
%6 = alloca i32
%7 = alloca i32
%8 = alloca i32
%9 = alloca i32
store %struct.pagetable* %0, %struct.pagetable** %4
store i32 %1, i32* %5
store i32 %2, i32* %6
%10 = load i32, i32* %6
%11 = udiv i32 %10, 4096
store i32 %11, i32* %7
%12 = load i32, i32* %6
%13 = urem i32 %12, 4096
%14 = icmp ne i32 %13, 0
br i1 %14, label %15, label %18
15: ; preds = %3
%16 = load i32, i32* %7
%17 = add i32 %16, 1
store i32 %17, i32* %7
br label %18
18: ; preds = %15, %3
%19 = load i32, i32* %5
%20 = and i32 %19, -4096
store i32 %20, i32* %5
br label %21
21: ; preds = %42, %18
%22 = load i32, i32* %7
%23 = icmp ugt i32 %22, 0
br i1 %23, label %24, label %47
24: ; preds = %21
%25 = load %struct.pagetable*, %struct.pagetable** %4
%26 = load i32, i32* %5
%27 = call i64 @pagetable_getmap(%struct.pagetable* %25, i32 %26, i32* %8, i32* %9)
%28 = icmp ne i64 %27, 0
br i1 %28, label %29, label %42
29: ; preds = %24
%30 = load %struct.pagetable*, %struct.pagetable** %4
%31 = load i32, i32* %5
%32 = call i32 @pagetable_unmap(%struct.pagetable* %30, i32 %31)
%33 = load i32, i32* %9
%34 = and i32 %33, 2
%35 = icmp ne i32 %34, 0
br i1 %35, label %36, label %41
36: ; preds = %29
%37 = load i32, i32* %8
%38 = zext i32 %37 to i64
%39 = inttoptr i64 %38 to i8*
%40 = call i32 @page_free(i8* %39)
br label %41
41: ; preds = %36, %29
br label %42
42: ; preds = %41, %24
%43 = load i32, i32* %5
%44 = add i32 %43, 4096
store i32 %44, i32* %5
%45 = load i32, i32* %7
%46 = add i32 %45, -1
store i32 %46, i32* %7
br label %21
47: ; preds = %21
ret void
}

LLVM IR (-O2):
%struct.pagetable = type { i32 }
define void @pagetable_free(%struct.pagetable* %0, i32 %1, i32 %2) {
%4 = alloca i32
%5 = alloca i32
%6 = lshr i32 %2, 12
%7 = and i32 %2, 4095
%8 = icmp ne i32 %7, 0
%9 = zext i1 %8 to i32
%10 = add nuw nsw i32 %6, %9
%11 = icmp eq i32 %10, 0
br i1 %11, label %35, label %12
12: ; preds = %3
%13 = and i32 %1, -4096
%14 = bitcast i32* %4 to i8*
%15 = bitcast i32* %5 to i8*
br label %16
16: ; preds = %12, %31
%17 = phi i32 [ %10, %12 ], [ %33, %31 ]
%18 = phi i32 [ %13, %12 ], [ %32, %31 ]
%19 = call i64 @pagetable_getmap(%struct.pagetable* %0, i32 %18, i32* %4, i32* %5)
%20 = icmp eq i64 %19, 0
br i1 %20, label %31, label %21
21: ; preds = %16
%22 = call i32 @pagetable_unmap(%struct.pagetable* %0, i32 %18)
%23 = load i32, i32* %5
%24 = and i32 %23, 2
%25 = icmp eq i32 %24, 0
br i1 %25, label %31, label %26
26: ; preds = %21
%27 = load i32, i32* %4
%28 = zext i32 %27 to i64
%29 = inttoptr i64 %28 to i8*
%30 = call i32 @page_free(i8* %29)
br label %31
31: ; preds = %21, %26, %16
%32 = add i32 %18, 4096
%33 = add nsw i32 %17, -1
%34 = icmp eq i32 %33, 0
br i1 %34, label %35, label %16
35: ; preds = %31, %3
ret void
}