// File: williewillus[P]panda_scratchpad/src/wrapper/workload.cpp
// Function: wrapper::WriteData(int, unsigned int, unsigned int)
int WriteData(int fd, unsigned int offset, unsigned int size) {
  // Offset into a data block to start working at.
  const unsigned int rounded_offset =
    (offset + (kTestDataSize - 1)) & (~(kTestDataSize - 1));
  // Round down size to 4k for number of full pages to write.
  
  const unsigned int aligned_size = (size >= kTestDataSize) ?
    (size - (rounded_offset - offset)) & ~(kTestDataSize - 1) :
    0;
  unsigned int num_written = 0;

  // The start of the write range is not aligned with our data blocks.
  // Therefore, we should write out part of a data block for this segment,
  // with the first character in the data block aligning with the data block
  // boundary.
  if (rounded_offset != offset) {
    // We should never write more than kTestDataSize of unaligned data at the
    // start.
    const unsigned int to_write = (size < rounded_offset - offset) ?
      size : rounded_offset - offset;
    while (num_written < to_write){
      const unsigned int mod_offset =
        (num_written + offset) & (kTestDataSize - 1);
      assert(mod_offset < kTestDataSize);

      int res = pwrite(fd, kTestDataBlock + mod_offset, to_write - num_written,
          offset + num_written);
      if (res < 0) {
        return res;
      }
      num_written += res;
    }
  }

  // Write out the required number of full pages for this request. The first
  // byte will be aligned with kTestDataSize.
  unsigned int aligned_written = 0;
  while (aligned_written < aligned_size) {
    const unsigned int mod_offset = (aligned_written & (kTestDataSize - 1));
    // Write up to a full page of data at a time.
    int res = pwrite(fd, kTestDataBlock + mod_offset,
        kTestDataSize - mod_offset, offset + num_written);
    if (res < 0) {
      return res;
    }
    num_written += res;
    aligned_written += res;
  } 

  if (num_written == size) {
    return 0;
  }

  // Write out the last partial page of data. The first byte will be aligned
  // with kTestDataSize.
  unsigned int end_written = 0;
  while (num_written < size) {
    assert(end_written < kTestDataSize);
    const unsigned int mod_offset = (end_written & (kTestDataSize - 1));
    int res = pwrite(fd, kTestDataBlock + mod_offset,
        size - num_written, offset + num_written);
    if (res < 0) {
      return res;
    }
    num_written += res;
    end_written += res;
  } 

  return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x50, %rsp
movl %edi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movl %edx, -0x10(%rbp)
movl -0xc(%rbp), %eax
addl $0xfff, %eax            # imm = 0xFFF
andl $0xfffff000, %eax       # imm = 0xFFFFF000
movl %eax, -0x14(%rbp)
cmpl $0x1000, -0x10(%rbp)    # imm = 0x1000
jb 0x1d25f
movl -0x10(%rbp), %eax
movl -0x14(%rbp), %ecx
subl -0xc(%rbp), %ecx
subl %ecx, %eax
andl $0xfffff000, %eax       # imm = 0xFFFFF000
movl %eax, -0x44(%rbp)
jmp 0x1d266
xorl %eax, %eax
movl %eax, -0x44(%rbp)
jmp 0x1d266
movl -0x44(%rbp), %eax
movl %eax, -0x18(%rbp)
movl $0x0, -0x1c(%rbp)
movl -0x14(%rbp), %eax
cmpl -0xc(%rbp), %eax
je 0x1d334
movl -0x10(%rbp), %eax
movl -0x14(%rbp), %ecx
subl -0xc(%rbp), %ecx
cmpl %ecx, %eax
jae 0x1d294
movl -0x10(%rbp), %eax
movl %eax, -0x48(%rbp)
jmp 0x1d29d
movl -0x14(%rbp), %eax
subl -0xc(%rbp), %eax
movl %eax, -0x48(%rbp)
movl -0x48(%rbp), %eax
movl %eax, -0x20(%rbp)
movl -0x1c(%rbp), %eax
cmpl -0x20(%rbp), %eax
jae 0x1d332
movl -0x1c(%rbp), %eax
addl -0xc(%rbp), %eax
andl $0xfff, %eax            # imm = 0xFFF
movl %eax, -0x24(%rbp)
cmpl $0x1000, -0x24(%rbp)    # imm = 0x1000
jae 0x1d2c8
jmp 0x1d2e7
leaq 0xbda4(%rip), %rdi      # 0x29073
leaq 0xbdb8(%rip), %rsi      # 0x2908e
movl $0x40, %edx
leaq 0xbdc1(%rip), %rcx      # 0x290a3
callq 0x19820
movl -0x8(%rbp), %edi
movl -0x24(%rbp), %eax
leaq 0xbe0c(%rip), %rsi      # 0x29100
addq %rax, %rsi
movl -0x20(%rbp), %eax
subl -0x1c(%rbp), %eax
movl %eax, %eax
movl %eax, %edx
movl -0xc(%rbp), %eax
addl -0x1c(%rbp), %eax
movl %eax, %eax
movl %eax, %ecx
callq 0x19300
movl %eax, -0x28(%rbp)
cmpl $0x0, -0x28(%rbp)
jge 0x1d324
movl -0x28(%rbp), %eax
movl %eax, -0x4(%rbp)
jmp 0x1d455
movl -0x28(%rbp), %eax
addl -0x1c(%rbp), %eax
movl %eax, -0x1c(%rbp)
jmp 0x1d2a3
jmp 0x1d334
movl $0x0, -0x2c(%rbp)
movl -0x2c(%rbp), %eax
cmpl -0x18(%rbp), %eax
jae 0x1d3a1
movl -0x2c(%rbp), %eax
andl $0xfff, %eax            # imm = 0xFFF
movl %eax, -0x30(%rbp)
movl -0x8(%rbp), %edi
movl -0x30(%rbp), %eax
leaq 0xbda5(%rip), %rsi      # 0x29100
addq %rax, %rsi
movl $0x1000, %eax           # imm = 0x1000
subl -0x30(%rbp), %eax
movl %eax, %eax
movl %eax, %edx
movl -0xc(%rbp), %eax
addl -0x1c(%rbp), %eax
movl %eax, %eax
movl %eax, %ecx
callq 0x19300
movl %eax, -0x34(%rbp)
cmpl $0x0, -0x34(%rbp)
jge 0x1d38d
movl -0x34(%rbp), %eax
movl %eax, -0x4(%rbp)
jmp 0x1d455
movl -0x34(%rbp), %eax
addl -0x1c(%rbp), %eax
movl %eax, -0x1c(%rbp)
movl -0x34(%rbp), %eax
addl -0x2c(%rbp), %eax
movl %eax, -0x2c(%rbp)
jmp 0x1d33b
movl -0x1c(%rbp), %eax
cmpl -0x10(%rbp), %eax
jne 0x1d3b5
movl $0x0, -0x4(%rbp)
jmp 0x1d455
movl $0x0, -0x38(%rbp)
movl -0x1c(%rbp), %eax
cmpl -0x10(%rbp), %eax
jae 0x1d44e
cmpl $0x1000, -0x38(%rbp)    # imm = 0x1000
jae 0x1d3d3
jmp 0x1d3f2
leaq 0xbd01(%rip), %rdi      # 0x290db
leaq 0xbcad(%rip), %rsi      # 0x2908e
movl $0x62, %edx
leaq 0xbcb6(%rip), %rcx      # 0x290a3
callq 0x19820
movl -0x38(%rbp), %eax
andl $0xfff, %eax            # imm = 0xFFF
movl %eax, -0x3c(%rbp)
movl -0x8(%rbp), %edi
movl -0x3c(%rbp), %eax
leaq 0xbcf6(%rip), %rsi      # 0x29100
addq %rax, %rsi
movl -0x10(%rbp), %eax
subl -0x1c(%rbp), %eax
movl %eax, %eax
movl %eax, %edx
movl -0xc(%rbp), %eax
addl -0x1c(%rbp), %eax
movl %eax, %eax
movl %eax, %ecx
callq 0x19300
movl %eax, -0x40(%rbp)
cmpl $0x0, -0x40(%rbp)
jge 0x1d437
movl -0x40(%rbp), %eax
movl %eax, -0x4(%rbp)
jmp 0x1d455
movl -0x40(%rbp), %eax
addl -0x1c(%rbp), %eax
movl %eax, -0x1c(%rbp)
movl -0x40(%rbp), %eax
addl -0x38(%rbp), %eax
movl %eax, -0x38(%rbp)
jmp 0x1d3bc
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x50, %rsp
popq %rbp
retq
nop