// File: lvandeve[P]lodepng/lodepng_unittest.cpp
// Function: md5sum(unsigned char const*, unsigned long, unsigned int*, unsigned int*, unsigned int*, unsigned int*)
void md5sum(const unsigned char* in, size_t size, unsigned* a0, unsigned* b0, unsigned* c0, unsigned* d0) {
  ASSERT_EQUALS(4, sizeof(unsigned));
  // per-round shift amounts
  static const unsigned s[64] = {
    7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,
    4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
  };
  // precomputed table from sines
  static const unsigned k[64] = {
    0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
    0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
    0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
    0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
    0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
    0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
    0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
    0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
  };

  *a0 = 0x67452301;
  *b0 = 0xefcdab89;
  *c0 = 0x98badcfe;
  *d0 = 0x10325476;

  // append bit, padding and size to input
  std::vector<unsigned char> data(in, in + size);
  data.resize(((size + 1 + 8 + 63) / 64) * 64, 0);
  data[size] = 128; // append 1 bit (msb)
  size_t bitsize = size * 8; // append the size (shifts > 31 are avoided)
  data[data.size() - 1] = ((bitsize >> 28u) >> 28u) & 255u;
  data[data.size() - 2] = ((bitsize >> 24u) >> 24u) & 255u;
  data[data.size() - 3] = ((bitsize >> 20u) >> 20u) & 255u;
  data[data.size() - 4] = ((bitsize >> 16u) >> 16u) & 255u;
  data[data.size() - 5] = (bitsize >> 24u) & 255u;
  data[data.size() - 6] = (bitsize >> 16u) & 255u;
  data[data.size() - 7] = (bitsize >> 8u) & 255u;
  data[data.size() - 8] = bitsize & 255u;

  // per chunk
  for(size_t i = 0; i < data.size(); i += 64) {
    unsigned a = *a0;
    unsigned b = *b0;
    unsigned c = *c0;
    unsigned d = *d0;

    for(size_t j = 0; j < 64; j++) {
      unsigned f, g;
      if(j <= 15u) {
        f = (b & c) | (~b & d);
        g = j;
      } else if(j <= 31u) {
        f = (d & b) | (~d & c);
        g = (5u * j + 1u) & 15u;
      } else if(j <= 47u) {
        f = b ^ c ^ d;
        g = (3u * j + 5u) & 15u;
      } else {
        f = c ^ (b | ~d);
        g = (7u * j) & 15u;
      }
      unsigned m = (unsigned)(data[i + g * 4 + 3] << 24u) | (unsigned)(data[i + g * 4 + 2] << 16u)
                 | (unsigned)(data[i + g * 4 + 1] << 8u) | (unsigned)data[i + g * 4];
      f += a + k[j] + m;
      a = d;
      d = c;
      c = b;
      b += leftrotate(f, s[j]);
    }
    *a0 += a;
    *b0 += b;
    *c0 += c;
    *d0 += d;
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x1c0, %rsp            # imm = 0x1C0
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq %r9, -0x30(%rbp)
movq -0x18(%rbp), %rax
movl $0x67452301, (%rax)     # imm = 0x67452301
movq -0x20(%rbp), %rax
movl $0xefcdab89, (%rax)     # imm = 0xEFCDAB89
movq -0x28(%rbp), %rax
movl $0x98badcfe, (%rax)     # imm = 0x98BADCFE
movq -0x30(%rbp), %rax
movl $0x10325476, (%rax)     # imm = 0x10325476
movq -0x8(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq -0x10(%rbp), %rcx
addq %rcx, %rax
movq %rax, -0xa8(%rbp)
leaq -0x49(%rbp), %rdi
movq %rdi, -0xa0(%rbp)
callq 0x1bfa0
movq -0xb0(%rbp), %rsi
movq -0xa8(%rbp), %rdx
movq -0xa0(%rbp), %rcx
leaq -0x48(%rbp), %rdi
callq 0x23350
jmp 0x29204
leaq -0x49(%rbp), %rdi
callq 0x1bff0
movq -0x10(%rbp), %rsi
addq $0x48, %rsi
andq $-0x40, %rsi
leaq -0x48(%rbp), %rdi
xorl %edx, %edx
callq 0x1a540
jmp 0x29226
movq -0x10(%rbp), %rsi
leaq -0x48(%rbp), %rdi
callq 0x1a5f0
movq %rax, -0xb8(%rbp)
jmp 0x2923c
movq -0xb8(%rbp), %rax
movb $-0x80, (%rax)
movq -0x10(%rbp), %rax
shlq $0x3, %rax
movq %rax, -0x68(%rbp)
movb -0x61(%rbp), %al
movb %al, -0xc1(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x1a400
movq %rax, -0xc0(%rbp)
jmp 0x2926d
movq -0xc0(%rbp), %rsi
decq %rsi
leaq -0x48(%rbp), %rdi
callq 0x1a5f0
movq %rax, -0xd0(%rbp)
jmp 0x29289
movq -0xd0(%rbp), %rax
movb -0xc1(%rbp), %cl
movb %cl, (%rax)
movb -0x62(%rbp), %al
movb %al, -0xd9(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x1a400
movq %rax, -0xd8(%rbp)
jmp 0x292b3
movq -0xd8(%rbp), %rsi
addq $-0x2, %rsi
leaq -0x48(%rbp), %rdi
callq 0x1a5f0
movq %rax, -0xe8(%rbp)
jmp 0x292d0
movq -0xe8(%rbp), %rax
movb -0xd9(%rbp), %cl
movb %cl, (%rax)
movb -0x63(%rbp), %al
movb %al, -0xf1(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x1a400
movq %rax, -0xf0(%rbp)
jmp 0x292fa
movq -0xf0(%rbp), %rsi
addq $-0x3, %rsi
leaq -0x48(%rbp), %rdi
callq 0x1a5f0
movq %rax, -0x100(%rbp)
jmp 0x29317
movq -0x100(%rbp), %rax
movb -0xf1(%rbp), %cl
movb %cl, (%rax)
movb -0x64(%rbp), %al
movb %al, -0x109(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x1a400
movq %rax, -0x108(%rbp)
jmp 0x29341
movq -0x108(%rbp), %rsi
addq $-0x4, %rsi
leaq -0x48(%rbp), %rdi
callq 0x1a5f0
movq %rax, -0x118(%rbp)
jmp 0x2935e
movq -0x118(%rbp), %rax
movb -0x109(%rbp), %cl
movb %cl, (%rax)
movb -0x65(%rbp), %al
movb %al, -0x121(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x1a400
movq %rax, -0x120(%rbp)
jmp 0x29388
movq -0x120(%rbp), %rsi
addq $-0x5, %rsi
leaq -0x48(%rbp), %rdi
callq 0x1a5f0
movq %rax, -0x130(%rbp)
jmp 0x293a5
movq -0x130(%rbp), %rax
movb -0x121(%rbp), %cl
movb %cl, (%rax)
movb -0x66(%rbp), %al
movb %al, -0x139(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x1a400
movq %rax, -0x138(%rbp)
jmp 0x293cf
movq -0x138(%rbp), %rsi
addq $-0x6, %rsi
leaq -0x48(%rbp), %rdi
callq 0x1a5f0
movq %rax, -0x148(%rbp)
jmp 0x293ec
movq -0x148(%rbp), %rax
movb -0x139(%rbp), %cl
movb %cl, (%rax)
movb -0x67(%rbp), %al
movb %al, -0x151(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x1a400
movq %rax, -0x150(%rbp)
jmp 0x29416
movq -0x150(%rbp), %rsi
addq $-0x7, %rsi
leaq -0x48(%rbp), %rdi
callq 0x1a5f0
movq %rax, -0x160(%rbp)
jmp 0x29433
movq -0x160(%rbp), %rax
movb -0x151(%rbp), %cl
movb %cl, (%rax)
movb -0x68(%rbp), %al
movb %al, -0x169(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x1a400
movq %rax, -0x168(%rbp)
jmp 0x2945d
movq -0x168(%rbp), %rsi
addq $-0x8, %rsi
leaq -0x48(%rbp), %rdi
callq 0x1a5f0
movq %rax, -0x178(%rbp)
jmp 0x2947a
movq -0x178(%rbp), %rax
movb -0x169(%rbp), %cl
movb %cl, (%rax)
movq $0x0, -0x70(%rbp)
movq -0x70(%rbp), %rax
movq %rax, -0x188(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x1a400
movq %rax, -0x180(%rbp)
jmp 0x294ae
movq -0x188(%rbp), %rax
movq -0x180(%rbp), %rcx
cmpq %rcx, %rax
jae 0x2979c
movq -0x18(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x74(%rbp)
movq -0x20(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x78(%rbp)
movq -0x28(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x7c(%rbp)
movq -0x30(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x80(%rbp)
movq $0x0, -0x88(%rbp)
cmpq $0x40, -0x88(%rbp)
jae 0x2975f
cmpq $0xf, -0x88(%rbp)
ja 0x29569
movl -0x78(%rbp), %eax
andl -0x7c(%rbp), %eax
movl -0x78(%rbp), %ecx
xorl $-0x1, %ecx
andl -0x80(%rbp), %ecx
orl %ecx, %eax
movl %eax, -0x8c(%rbp)
movq -0x88(%rbp), %rax
movl %eax, -0x90(%rbp)
jmp 0x295ff
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
leaq -0x49(%rbp), %rdi
callq 0x1bff0
jmp 0x297b0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x1a4c0
jmp 0x297ae
cmpq $0x1f, -0x88(%rbp)
ja 0x295a2
movl -0x80(%rbp), %eax
andl -0x78(%rbp), %eax
movl -0x80(%rbp), %ecx
xorl $-0x1, %ecx
andl -0x7c(%rbp), %ecx
orl %ecx, %eax
movl %eax, -0x8c(%rbp)
imulq $0x5, -0x88(%rbp), %rax
addq $0x1, %rax
andq $0xf, %rax
movl %eax, -0x90(%rbp)
jmp 0x295fd
cmpq $0x2f, -0x88(%rbp)
ja 0x295d3
movl -0x78(%rbp), %eax
xorl -0x7c(%rbp), %eax
xorl -0x80(%rbp), %eax
movl %eax, -0x8c(%rbp)
imulq $0x3, -0x88(%rbp), %rax
addq $0x5, %rax
andq $0xf, %rax
movl %eax, -0x90(%rbp)
jmp 0x295fb
movl -0x7c(%rbp), %eax
movl -0x78(%rbp), %ecx
movl -0x80(%rbp), %edx
xorl $-0x1, %edx
orl %edx, %ecx
xorl %ecx, %eax
movl %eax, -0x8c(%rbp)
imulq $0x7, -0x88(%rbp), %rax
andq $0xf, %rax
movl %eax, -0x90(%rbp)
jmp 0x295fd
jmp 0x295ff
movq -0x70(%rbp), %rax
movl -0x90(%rbp), %ecx
shll $0x2, %ecx
leaq 0x3(%rax,%rcx), %rsi
leaq -0x48(%rbp), %rdi
callq 0x1a5f0
movq %rax, -0x190(%rbp)
jmp 0x29623
movq -0x190(%rbp), %rax
movzbl (%rax), %eax
shll $0x18, %eax
movl %eax, -0x19c(%rbp)
movq -0x70(%rbp), %rax
movl -0x90(%rbp), %ecx
shll $0x2, %ecx
leaq 0x2(%rax,%rcx), %rsi
leaq -0x48(%rbp), %rdi
callq 0x1a5f0
movq %rax, -0x198(%rbp)
jmp 0x2965a
movl -0x19c(%rbp), %eax
movq -0x198(%rbp), %rcx
movzbl (%rcx), %ecx
shll $0x10, %ecx
orl %ecx, %eax
movl %eax, -0x1ac(%rbp)
movq -0x70(%rbp), %rax
movl -0x90(%rbp), %ecx
shll $0x2, %ecx
leaq 0x1(%rax,%rcx), %rsi
leaq -0x48(%rbp), %rdi
callq 0x1a5f0
movq %rax, -0x1a8(%rbp)
jmp 0x29699
movl -0x1ac(%rbp), %eax
movq -0x1a8(%rbp), %rcx
movzbl (%rcx), %ecx
shll $0x8, %ecx
orl %ecx, %eax
movl %eax, -0x1bc(%rbp)
movq -0x70(%rbp), %rsi
movl -0x90(%rbp), %eax
shll $0x2, %eax
addq %rax, %rsi
leaq -0x48(%rbp), %rdi
callq 0x1a5f0
movq %rax, -0x1b8(%rbp)
jmp 0x296d6
movl -0x1bc(%rbp), %eax
movq -0x1b8(%rbp), %rcx
movzbl (%rcx), %ecx
orl %ecx, %eax
movl %eax, -0x94(%rbp)
movl -0x74(%rbp), %eax
movq -0x88(%rbp), %rdx
leaq 0x89741(%rip), %rcx     # 0xb2e40
addl (%rcx,%rdx,4), %eax
addl -0x94(%rbp), %eax
addl -0x8c(%rbp), %eax
movl %eax, -0x8c(%rbp)
movl -0x80(%rbp), %eax
movl %eax, -0x74(%rbp)
movl -0x7c(%rbp), %eax
movl %eax, -0x80(%rbp)
movl -0x78(%rbp), %eax
movl %eax, -0x7c(%rbp)
movl -0x8c(%rbp), %edi
movq -0x88(%rbp), %rcx
leaq 0x89606(%rip), %rax     # 0xb2d40
movl (%rax,%rcx,4), %esi
callq 0x29140
addl -0x78(%rbp), %eax
movl %eax, -0x78(%rbp)
movq -0x88(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x88(%rbp)
jmp 0x294f4
movl -0x74(%rbp), %ecx
movq -0x18(%rbp), %rax
addl (%rax), %ecx
movl %ecx, (%rax)
movl -0x78(%rbp), %ecx
movq -0x20(%rbp), %rax
addl (%rax), %ecx
movl %ecx, (%rax)
movl -0x7c(%rbp), %ecx
movq -0x28(%rbp), %rax
addl (%rax), %ecx
movl %ecx, (%rax)
movl -0x80(%rbp), %ecx
movq -0x30(%rbp), %rax
addl (%rax), %ecx
movl %ecx, (%rax)
movq -0x70(%rbp), %rax
addq $0x40, %rax
movq %rax, -0x70(%rbp)
jmp 0x29491
leaq -0x48(%rbp), %rdi
callq 0x1a4c0
addq $0x1c0, %rsp            # imm = 0x1C0
popq %rbp
retq
jmp 0x297b0
movq -0x58(%rbp), %rdi
callq 0x3430
movq %rax, %rdi
callq 0x1a490
nopw %cs:(%rax,%rax)