// File: BU-DiSC[P]BF-Shared-Hashing/hash/city.cc
// Function: CityHash128WithSeed(char const*, unsigned long, std::pair<unsigned long, unsigned long>)
uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) {
  if (len < 128) {
    return CityMurmur(s, len, seed);
  }

  // We expect len >= 128 to be the common case.  Keep 56 bytes of state:
  // v, w, x, y, and z.
  pair<uint64, uint64> v, w;
  uint64 x = Uint128Low64(seed);
  uint64 y = Uint128High64(seed);
  uint64 z = len * k1;
  v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s);
  v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8);
  w.first = Rotate(y + z, 35) * k1 + x;
  w.second = Rotate(x + Fetch64(s + 88), 53) * k1;

  // This is the same inner loop as CityHash64(), manually unrolled.
  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;
    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 -= 128;
  } while (LIKELY(len >= 128));
  x += Rotate(v.first + z, 49) * k0;
  y = y * k0 + Rotate(w.second, 37);
  z = z * k0 + Rotate(w.first, 27);
  w.first *= 9;
  v.first *= k0;
  // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
  for (size_t tail_done = 0; tail_done < len; ) {
    tail_done += 32;
    y = Rotate(x + y, 42) * k0 + v.second;
    w.first += Fetch64(s + len - tail_done + 16);
    x = x * k0 + w.first;
    z += w.second + Fetch64(s + len - tail_done);
    w.second += v.first;
    v = WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second);
    v.first *= k0;
  }
  // At this point our 56 bytes of state should contain more than
  // enough information for a strong 128-bit hash.  We use two
  // different 56-byte-to-8-byte hashes to get a 16-byte final result.
  x = HashLen16(x, v.first);
  y = HashLen16(y + z, w.first);
  return uint128(HashLen16(x + v.second, w.second) + y,
                 HashLen16(x + w.second, y + v.second));
}

// Assembly:
subq $0x178, %rsp            # imm = 0x178
movq %rdx, 0x158(%rsp)
movq %rcx, 0x160(%rsp)
movq %rdi, 0x150(%rsp)
movq %rsi, 0x148(%rsp)
cmpq $0x80, 0x148(%rsp)
jae 0x626ef
movq 0x150(%rsp), %rdi
movq 0x148(%rsp), %rsi
movq 0x158(%rsp), %rax
movq %rax, 0x138(%rsp)
movq 0x160(%rsp), %rax
movq %rax, 0x140(%rsp)
movq 0x138(%rsp), %rdx
movq 0x140(%rsp), %rcx
callq 0x63040
movq %rax, 0x168(%rsp)
movq %rdx, 0x170(%rsp)
jmp 0x63023
leaq 0x128(%rsp), %rdi
callq 0x637f0
leaq 0x118(%rsp), %rdi
callq 0x637f0
leaq 0x158(%rsp), %rdi
callq 0x63810
movq %rax, 0x110(%rsp)
leaq 0x158(%rsp), %rdi
callq 0x63820
movq %rax, 0x108(%rsp)
movabsq $-0x4b6d499041670d8d, %rax # imm = 0xB492B66FBE98F273
imulq 0x148(%rsp), %rax
movq %rax, 0x100(%rsp)
movabsq $-0x4b6d499041670d8d, %rdi # imm = 0xB492B66FBE98F273
xorq 0x108(%rsp), %rdi
movl $0x31, %esi
callq 0x62570
movabsq $-0x4b6d499041670d8d, %rcx # imm = 0xB492B66FBE98F273
imulq %rcx, %rax
movq %rax, 0x80(%rsp)
movq 0x150(%rsp), %rdi
callq 0x62490
movq %rax, %rcx
movq 0x80(%rsp), %rax
addq %rcx, %rax
movq %rax, 0x128(%rsp)
movq 0x128(%rsp), %rdi
movl $0x2a, %esi
callq 0x62570
movabsq $-0x4b6d499041670d8d, %rcx # imm = 0xB492B66FBE98F273
imulq %rcx, %rax
movq %rax, 0x88(%rsp)
movq 0x150(%rsp), %rdi
addq $0x8, %rdi
callq 0x62490
movq %rax, %rcx
movq 0x88(%rsp), %rax
addq %rcx, %rax
movq %rax, 0x130(%rsp)
movq 0x108(%rsp), %rdi
addq 0x100(%rsp), %rdi
movl $0x23, %esi
callq 0x62570
movabsq $-0x4b6d499041670d8d, %rcx # imm = 0xB492B66FBE98F273
imulq %rcx, %rax
addq 0x110(%rsp), %rax
movq %rax, 0x118(%rsp)
movq 0x110(%rsp), %rax
movq %rax, 0x90(%rsp)
movq 0x150(%rsp), %rdi
addq $0x58, %rdi
callq 0x62490
movq 0x90(%rsp), %rdi
addq %rax, %rdi
movl $0x35, %esi
callq 0x62570
movabsq $-0x4b6d499041670d8d, %rcx # imm = 0xB492B66FBE98F273
imulq %rcx, %rax
movq %rax, 0x120(%rsp)
movq 0x110(%rsp), %rax
addq 0x108(%rsp), %rax
addq 0x128(%rsp), %rax
movq %rax, 0x20(%rsp)
movq 0x150(%rsp), %rdi
addq $0x8, %rdi
callq 0x62490
movq 0x20(%rsp), %rdi
addq %rax, %rdi
movl $0x25, %esi
callq 0x62570
movabsq $-0x4b6d499041670d8d, %rcx # imm = 0xB492B66FBE98F273
imulq %rcx, %rax
movq %rax, 0x110(%rsp)
movq 0x108(%rsp), %rax
addq 0x130(%rsp), %rax
movq %rax, 0x28(%rsp)
movq 0x150(%rsp), %rdi
addq $0x30, %rdi
callq 0x62490
movq 0x28(%rsp), %rdi
addq %rax, %rdi
movl $0x2a, %esi
callq 0x62570
movabsq $-0x4b6d499041670d8d, %rcx # imm = 0xB492B66FBE98F273
imulq %rcx, %rax
movq %rax, 0x108(%rsp)
movq 0x120(%rsp), %rax
xorq 0x110(%rsp), %rax
movq %rax, 0x110(%rsp)
movq 0x128(%rsp), %rax
movq %rax, 0x30(%rsp)
movq 0x150(%rsp), %rdi
addq $0x28, %rdi
callq 0x62490
movq %rax, %rcx
movq 0x30(%rsp), %rax
addq %rcx, %rax
addq 0x108(%rsp), %rax
movq %rax, 0x108(%rsp)
movq 0x100(%rsp), %rdi
addq 0x118(%rsp), %rdi
movl $0x21, %esi
callq 0x62570
movabsq $-0x4b6d499041670d8d, %rcx # imm = 0xB492B66FBE98F273
imulq %rcx, %rax
movq %rax, 0x100(%rsp)
movq 0x150(%rsp), %rdi
movabsq $-0x4b6d499041670d8d, %rsi # imm = 0xB492B66FBE98F273
imulq 0x130(%rsp), %rsi
movq 0x110(%rsp), %rdx
addq 0x118(%rsp), %rdx
callq 0x624e0
movq %rax, 0xf0(%rsp)
movq %rdx, 0xf8(%rsp)
leaq 0x128(%rsp), %rdi
leaq 0xf0(%rsp), %rsi
callq 0x63780
movq 0x150(%rsp), %rax
addq $0x20, %rax
movq %rax, 0x40(%rsp)
movq 0x100(%rsp), %rax
addq 0x120(%rsp), %rax
movq %rax, 0x48(%rsp)
movq 0x108(%rsp), %rax
movq %rax, 0x38(%rsp)
movq 0x150(%rsp), %rdi
addq $0x10, %rdi
callq 0x62490
movq 0x38(%rsp), %rdx
movq 0x40(%rsp), %rdi
movq 0x48(%rsp), %rsi
addq %rax, %rdx
callq 0x624e0
movq %rax, 0xe0(%rsp)
movq %rdx, 0xe8(%rsp)
leaq 0x118(%rsp), %rdi
leaq 0xe0(%rsp), %rsi
callq 0x63780
leaq 0x100(%rsp), %rdi
leaq 0x110(%rsp), %rsi
callq 0x637b0
movq 0x150(%rsp), %rax
addq $0x40, %rax
movq %rax, 0x150(%rsp)
movq 0x110(%rsp), %rax
addq 0x108(%rsp), %rax
addq 0x128(%rsp), %rax
movq %rax, 0x50(%rsp)
movq 0x150(%rsp), %rdi
addq $0x8, %rdi
callq 0x62490
movq 0x50(%rsp), %rdi
addq %rax, %rdi
movl $0x25, %esi
callq 0x62570
movabsq $-0x4b6d499041670d8d, %rcx # imm = 0xB492B66FBE98F273
imulq %rcx, %rax
movq %rax, 0x110(%rsp)
movq 0x108(%rsp), %rax
addq 0x130(%rsp), %rax
movq %rax, 0x58(%rsp)
movq 0x150(%rsp), %rdi
addq $0x30, %rdi
callq 0x62490
movq 0x58(%rsp), %rdi
addq %rax, %rdi
movl $0x2a, %esi
callq 0x62570
movabsq $-0x4b6d499041670d8d, %rcx # imm = 0xB492B66FBE98F273
imulq %rcx, %rax
movq %rax, 0x108(%rsp)
movq 0x120(%rsp), %rax
xorq 0x110(%rsp), %rax
movq %rax, 0x110(%rsp)
movq 0x128(%rsp), %rax
movq %rax, 0x60(%rsp)
movq 0x150(%rsp), %rdi
addq $0x28, %rdi
callq 0x62490
movq %rax, %rcx
movq 0x60(%rsp), %rax
addq %rcx, %rax
addq 0x108(%rsp), %rax
movq %rax, 0x108(%rsp)
movq 0x100(%rsp), %rdi
addq 0x118(%rsp), %rdi
movl $0x21, %esi
callq 0x62570
movabsq $-0x4b6d499041670d8d, %rcx # imm = 0xB492B66FBE98F273
imulq %rcx, %rax
movq %rax, 0x100(%rsp)
movq 0x150(%rsp), %rdi
movabsq $-0x4b6d499041670d8d, %rsi # imm = 0xB492B66FBE98F273
imulq 0x130(%rsp), %rsi
movq 0x110(%rsp), %rdx
addq 0x118(%rsp), %rdx
callq 0x624e0
movq %rax, 0xd0(%rsp)
movq %rdx, 0xd8(%rsp)
leaq 0x128(%rsp), %rdi
leaq 0xd0(%rsp), %rsi
callq 0x63780
movq 0x150(%rsp), %rax
addq $0x20, %rax
movq %rax, 0x70(%rsp)
movq 0x100(%rsp), %rax
addq 0x120(%rsp), %rax
movq %rax, 0x78(%rsp)
movq 0x108(%rsp), %rax
movq %rax, 0x68(%rsp)
movq 0x150(%rsp), %rdi
addq $0x10, %rdi
callq 0x62490
movq 0x68(%rsp), %rdx
movq 0x70(%rsp), %rdi
movq 0x78(%rsp), %rsi
addq %rax, %rdx
callq 0x624e0
movq %rax, 0xc0(%rsp)
movq %rdx, 0xc8(%rsp)
leaq 0x118(%rsp), %rdi
leaq 0xc0(%rsp), %rsi
callq 0x63780
leaq 0x100(%rsp), %rdi
leaq 0x110(%rsp), %rsi
callq 0x637b0
movq 0x150(%rsp), %rax
addq $0x40, %rax
movq %rax, 0x150(%rsp)
movq 0x148(%rsp), %rax
subq $0x80, %rax
movq %rax, 0x148(%rsp)
cmpq $0x80, 0x148(%rsp)
jae 0x62876
movq 0x128(%rsp), %rdi
addq 0x100(%rsp), %rdi
movl $0x31, %esi
callq 0x62570
movabsq $-0x3c5a37a36834ced9, %rcx # imm = 0xC3A5C85C97CB3127
imulq %rcx, %rax
addq 0x110(%rsp), %rax
movq %rax, 0x110(%rsp)
movabsq $-0x3c5a37a36834ced9, %rax # imm = 0xC3A5C85C97CB3127
imulq 0x108(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x120(%rsp), %rdi
movl $0x25, %esi
callq 0x62570
movq %rax, %rcx
movq 0x10(%rsp), %rax
addq %rcx, %rax
movq %rax, 0x108(%rsp)
movabsq $-0x3c5a37a36834ced9, %rax # imm = 0xC3A5C85C97CB3127
imulq 0x100(%rsp), %rax
movq %rax, 0x18(%rsp)
movq 0x118(%rsp), %rdi
movl $0x1b, %esi
callq 0x62570
movq %rax, %rcx
movq 0x18(%rsp), %rax
addq %rcx, %rax
movq %rax, 0x100(%rsp)
imulq $0x9, 0x118(%rsp), %rax
movq %rax, 0x118(%rsp)
movabsq $-0x3c5a37a36834ced9, %rax # imm = 0xC3A5C85C97CB3127
imulq 0x128(%rsp), %rax
movq %rax, 0x128(%rsp)
movq $0x0, 0xb8(%rsp)
movq 0xb8(%rsp), %rax
cmpq 0x148(%rsp), %rax
jae 0x62f6a
movq 0xb8(%rsp), %rax
addq $0x20, %rax
movq %rax, 0xb8(%rsp)
movq 0x110(%rsp), %rdi
addq 0x108(%rsp), %rdi
movl $0x2a, %esi
callq 0x62570
movabsq $-0x3c5a37a36834ced9, %rcx # imm = 0xC3A5C85C97CB3127
imulq %rcx, %rax
addq 0x130(%rsp), %rax
movq %rax, 0x108(%rsp)
movq 0x150(%rsp), %rdi
addq 0x148(%rsp), %rdi
xorl %eax, %eax
subq 0xb8(%rsp), %rax
addq %rax, %rdi
addq $0x10, %rdi
callq 0x62490
addq 0x118(%rsp), %rax
movq %rax, 0x118(%rsp)
movabsq $-0x3c5a37a36834ced9, %rax # imm = 0xC3A5C85C97CB3127
imulq 0x110(%rsp), %rax
addq 0x118(%rsp), %rax
movq %rax, 0x110(%rsp)
movq 0x120(%rsp), %rax
movq %rax, 0x8(%rsp)
movq 0x150(%rsp), %rdi
addq 0x148(%rsp), %rdi
xorl %eax, %eax
subq 0xb8(%rsp), %rax
addq %rax, %rdi
callq 0x62490
movq %rax, %rcx
movq 0x8(%rsp), %rax
addq %rcx, %rax
addq 0x100(%rsp), %rax
movq %rax, 0x100(%rsp)
movq 0x128(%rsp), %rax
addq 0x120(%rsp), %rax
movq %rax, 0x120(%rsp)
movq 0x150(%rsp), %rdi
addq 0x148(%rsp), %rdi
xorl %eax, %eax
subq 0xb8(%rsp), %rax
addq %rax, %rdi
movq 0x128(%rsp), %rsi
addq 0x100(%rsp), %rsi
movq 0x130(%rsp), %rdx
callq 0x624e0
movq %rax, 0xa8(%rsp)
movq %rdx, 0xb0(%rsp)
leaq 0x128(%rsp), %rdi
leaq 0xa8(%rsp), %rsi
callq 0x63780
movabsq $-0x3c5a37a36834ced9, %rax # imm = 0xC3A5C85C97CB3127
imulq 0x128(%rsp), %rax
movq %rax, 0x128(%rsp)
jmp 0x62dce
movq 0x110(%rsp), %rdi
movq 0x128(%rsp), %rsi
callq 0x624a0
movq %rax, 0x110(%rsp)
movq 0x108(%rsp), %rdi
addq 0x100(%rsp), %rdi
movq 0x118(%rsp), %rsi
callq 0x624a0
movq %rax, 0x108(%rsp)
movq 0x110(%rsp), %rdi
addq 0x130(%rsp), %rdi
movq 0x120(%rsp), %rsi
callq 0x624a0
addq 0x108(%rsp), %rax
movq %rax, 0xa0(%rsp)
movq 0x110(%rsp), %rdi
addq 0x120(%rsp), %rdi
movq 0x108(%rsp), %rsi
addq 0x130(%rsp), %rsi
callq 0x624a0
movq %rax, 0x98(%rsp)
leaq 0x168(%rsp), %rdi
leaq 0xa0(%rsp), %rsi
leaq 0x98(%rsp), %rdx
callq 0x63830
movq 0x168(%rsp), %rax
movq 0x170(%rsp), %rdx
addq $0x178, %rsp            # imm = 0x178
retq
nopl (%rax,%rax)