// File: BU-DiSC[P]BF-Shared-Hashing/hash/city.cc
// Function: CityHash64(char const*, unsigned long)
uint64 CityHash64(const char *s, size_t len) {
  if (len <= 32) {
    if (len <= 16) {
      return HashLen0to16(s, len);
    } else {
      return HashLen17to32(s, len);
    }
  } else if (len <= 64) {
    return HashLen33to64(s, len);
  }

  // For strings over 64 bytes we hash the end first, and then as we
  // loop we keep 56 bytes of state: v, w, x, y, and z.
  uint64 x = Fetch64(s + len - 40);
  uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
  uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
  pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
  pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
  x = x * k1 + Fetch64(s);

  // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
  len = (len - 1) & ~static_cast<size_t>(63);
  do {
    x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
    y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
    x ^= w.second;
    y += v.first + Fetch64(s + 40);
    z = Rotate(z + w.first, 33) * k1;
    v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
    w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
    std::swap(z, x);
    s += 64;
    len -= 64;
  } while (len != 0);
  return HashLen16(HashLen16(v.first, w.first) + ShiftMix(y) * k1 + z,
                   HashLen16(v.second, w.second) + x);
}

// Assembly:
subq $0xc8, %rsp
movq %rdi, 0xb8(%rsp)
movq %rsi, 0xb0(%rsp)
cmpq $0x20, 0xb0(%rsp)
ja 0x61a81
cmpq $0x10, 0xb0(%rsp)
ja 0x61a5f
movq 0xb8(%rsp), %rdi
movq 0xb0(%rsp), %rsi
callq 0x61ef0
movq %rax, 0xc0(%rsp)
jmp 0x61edd
movq 0xb8(%rsp), %rdi
movq 0xb0(%rsp), %rsi
callq 0x620f0
movq %rax, 0xc0(%rsp)
jmp 0x61edd
cmpq $0x40, 0xb0(%rsp)
ja 0x61aae
movq 0xb8(%rsp), %rdi
movq 0xb0(%rsp), %rsi
callq 0x62210
movq %rax, 0xc0(%rsp)
jmp 0x61edd
jmp 0x61ab0
movq 0xb8(%rsp), %rdi
addq 0xb0(%rsp), %rdi
addq $-0x28, %rdi
callq 0x62490
movq %rax, 0xa8(%rsp)
movq 0xb8(%rsp), %rdi
addq 0xb0(%rsp), %rdi
addq $-0x10, %rdi
callq 0x62490
movq %rax, 0x40(%rsp)
movq 0xb8(%rsp), %rdi
addq 0xb0(%rsp), %rdi
addq $-0x38, %rdi
callq 0x62490
movq %rax, %rcx
movq 0x40(%rsp), %rax
addq %rcx, %rax
movq %rax, 0xa0(%rsp)
movq 0xb8(%rsp), %rdi
addq 0xb0(%rsp), %rdi
addq $-0x30, %rdi
callq 0x62490
addq 0xb0(%rsp), %rax
movq %rax, 0x48(%rsp)
movq 0xb8(%rsp), %rdi
addq 0xb0(%rsp), %rdi
addq $-0x18, %rdi
callq 0x62490
movq 0x48(%rsp), %rdi
movq %rax, %rsi
callq 0x624a0
movq %rax, 0x98(%rsp)
movq 0xb8(%rsp), %rdi
addq 0xb0(%rsp), %rdi
addq $-0x40, %rdi
movq 0xb0(%rsp), %rsi
movq 0x98(%rsp), %rdx
callq 0x624e0
movq %rax, 0x88(%rsp)
movq %rdx, 0x90(%rsp)
movq 0xb8(%rsp), %rdi
addq 0xb0(%rsp), %rdi
addq $-0x20, %rdi
movabsq $-0x4b6d499041670d8d, %rsi # imm = 0xB492B66FBE98F273
addq 0xa0(%rsp), %rsi
movq 0xa8(%rsp), %rdx
callq 0x624e0
movq %rax, 0x78(%rsp)
movq %rdx, 0x80(%rsp)
movabsq $-0x4b6d499041670d8d, %rax # imm = 0xB492B66FBE98F273
imulq 0xa8(%rsp), %rax
movq %rax, 0x50(%rsp)
movq 0xb8(%rsp), %rdi
callq 0x62490
movq %rax, %rcx
movq 0x50(%rsp), %rax
addq %rcx, %rax
movq %rax, 0xa8(%rsp)
movq 0xb0(%rsp), %rax
subq $0x1, %rax
andq $-0x40, %rax
movq %rax, 0xb0(%rsp)
movq 0xa8(%rsp), %rax
addq 0xa0(%rsp), %rax
addq 0x88(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0xb8(%rsp), %rdi
addq $0x8, %rdi
callq 0x62490
movq 0x10(%rsp), %rdi
addq %rax, %rdi
movl $0x25, %esi
callq 0x62570
movabsq $-0x4b6d499041670d8d, %rcx # imm = 0xB492B66FBE98F273
imulq %rcx, %rax
movq %rax, 0xa8(%rsp)
movq 0xa0(%rsp), %rax
addq 0x90(%rsp), %rax
movq %rax, 0x18(%rsp)
movq 0xb8(%rsp), %rdi
addq $0x30, %rdi
callq 0x62490
movq 0x18(%rsp), %rdi
addq %rax, %rdi
movl $0x2a, %esi
callq 0x62570
movabsq $-0x4b6d499041670d8d, %rcx # imm = 0xB492B66FBE98F273
imulq %rcx, %rax
movq %rax, 0xa0(%rsp)
movq 0x80(%rsp), %rax
xorq 0xa8(%rsp), %rax
movq %rax, 0xa8(%rsp)
movq 0x88(%rsp), %rax
movq %rax, 0x20(%rsp)
movq 0xb8(%rsp), %rdi
addq $0x28, %rdi
callq 0x62490
movq %rax, %rcx
movq 0x20(%rsp), %rax
addq %rcx, %rax
addq 0xa0(%rsp), %rax
movq %rax, 0xa0(%rsp)
movq 0x98(%rsp), %rdi
addq 0x78(%rsp), %rdi
movl $0x21, %esi
callq 0x62570
movabsq $-0x4b6d499041670d8d, %rcx # imm = 0xB492B66FBE98F273
imulq %rcx, %rax
movq %rax, 0x98(%rsp)
movq 0xb8(%rsp), %rdi
movabsq $-0x4b6d499041670d8d, %rsi # imm = 0xB492B66FBE98F273
imulq 0x90(%rsp), %rsi
movq 0xa8(%rsp), %rdx
addq 0x78(%rsp), %rdx
callq 0x624e0
movq %rax, 0x68(%rsp)
movq %rdx, 0x70(%rsp)
leaq 0x88(%rsp), %rdi
leaq 0x68(%rsp), %rsi
callq 0x63780
movq 0xb8(%rsp), %rax
addq $0x20, %rax
movq %rax, 0x30(%rsp)
movq 0x98(%rsp), %rax
addq 0x80(%rsp), %rax
movq %rax, 0x38(%rsp)
movq 0xa0(%rsp), %rax
movq %rax, 0x28(%rsp)
movq 0xb8(%rsp), %rdi
addq $0x10, %rdi
callq 0x62490
movq 0x28(%rsp), %rdx
movq 0x30(%rsp), %rdi
movq 0x38(%rsp), %rsi
addq %rax, %rdx
callq 0x624e0
movq %rax, 0x58(%rsp)
movq %rdx, 0x60(%rsp)
leaq 0x78(%rsp), %rdi
leaq 0x58(%rsp), %rsi
callq 0x63780
leaq 0x98(%rsp), %rdi
leaq 0xa8(%rsp), %rsi
callq 0x637b0
movq 0xb8(%rsp), %rax
addq $0x40, %rax
movq %rax, 0xb8(%rsp)
movq 0xb0(%rsp), %rax
subq $0x40, %rax
movq %rax, 0xb0(%rsp)
cmpq $0x0, 0xb0(%rsp)
jne 0x61c38
movq 0x88(%rsp), %rdi
movq 0x78(%rsp), %rsi
callq 0x624a0
movq %rax, (%rsp)
movq 0xa0(%rsp), %rdi
callq 0x625c0
movq %rax, %rcx
movq (%rsp), %rax
movabsq $-0x4b6d499041670d8d, %rdx # imm = 0xB492B66FBE98F273
imulq %rdx, %rcx
addq %rcx, %rax
addq 0x98(%rsp), %rax
movq %rax, 0x8(%rsp)
movq 0x90(%rsp), %rdi
movq 0x80(%rsp), %rsi
callq 0x624a0
movq 0x8(%rsp), %rdi
movq %rax, %rsi
addq 0xa8(%rsp), %rsi
callq 0x624a0
movq %rax, 0xc0(%rsp)
movq 0xc0(%rsp), %rax
addq $0xc8, %rsp
retq
nopl (%rax)