// File: BU-DiSC[P]BF-Shared-Hashing/hash/Crc32.cpp
// Function: crc32_16bytes_prefetch(void const*, unsigned long, unsigned int, unsigned long)
uint32_t crc32_16bytes_prefetch(const void* data, size_t length, uint32_t previousCrc32, size_t prefetchAhead)
{
  // CRC code is identical to crc32_16bytes (including unrolling), only added prefetching
  // 256 bytes look-ahead seems to be the sweet spot on Core i7 CPUs

  uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF
  const uint32_t* current = (const uint32_t*) data;

  // enabling optimization (at least -O2) automatically unrolls the for-loop
  const size_t Unroll = 4;
  const size_t BytesAtOnce = 16 * Unroll;

  while (length >= BytesAtOnce + prefetchAhead)
  {
    PREFETCH(((const char*) current) + prefetchAhead);

    for (size_t unrolling = 0; unrolling < Unroll; unrolling++)
    {
#if __BYTE_ORDER == __BIG_ENDIAN
    uint32_t one   = *current++ ^ swap(crc);
    uint32_t two   = *current++;
    uint32_t three = *current++;
    uint32_t four  = *current++;
    crc  = Crc32Lookup[ 0][ four         & 0xFF] ^
           Crc32Lookup[ 1][(four  >>  8) & 0xFF] ^
           Crc32Lookup[ 2][(four  >> 16) & 0xFF] ^
           Crc32Lookup[ 3][(four  >> 24) & 0xFF] ^
           Crc32Lookup[ 4][ three        & 0xFF] ^
           Crc32Lookup[ 5][(three >>  8) & 0xFF] ^
           Crc32Lookup[ 6][(three >> 16) & 0xFF] ^
           Crc32Lookup[ 7][(three >> 24) & 0xFF] ^
           Crc32Lookup[ 8][ two          & 0xFF] ^
           Crc32Lookup[ 9][(two   >>  8) & 0xFF] ^
           Crc32Lookup[10][(two   >> 16) & 0xFF] ^
           Crc32Lookup[11][(two   >> 24) & 0xFF] ^
           Crc32Lookup[12][ one          & 0xFF] ^
           Crc32Lookup[13][(one   >>  8) & 0xFF] ^
           Crc32Lookup[14][(one   >> 16) & 0xFF] ^
           Crc32Lookup[15][(one   >> 24) & 0xFF];
#else
    uint32_t one   = *current++ ^ crc;
    uint32_t two   = *current++;
    uint32_t three = *current++;
    uint32_t four  = *current++;
    crc  = Crc32Lookup[ 0][(four  >> 24) & 0xFF] ^
           Crc32Lookup[ 1][(four  >> 16) & 0xFF] ^
           Crc32Lookup[ 2][(four  >>  8) & 0xFF] ^
           Crc32Lookup[ 3][ four         & 0xFF] ^
           Crc32Lookup[ 4][(three >> 24) & 0xFF] ^
           Crc32Lookup[ 5][(three >> 16) & 0xFF] ^
           Crc32Lookup[ 6][(three >>  8) & 0xFF] ^
           Crc32Lookup[ 7][ three        & 0xFF] ^
           Crc32Lookup[ 8][(two   >> 24) & 0xFF] ^
           Crc32Lookup[ 9][(two   >> 16) & 0xFF] ^
           Crc32Lookup[10][(two   >>  8) & 0xFF] ^
           Crc32Lookup[11][ two          & 0xFF] ^
           Crc32Lookup[12][(one   >> 24) & 0xFF] ^
           Crc32Lookup[13][(one   >> 16) & 0xFF] ^
           Crc32Lookup[14][(one   >>  8) & 0xFF] ^
           Crc32Lookup[15][ one          & 0xFF];
#endif
    }

    length -= BytesAtOnce;
  }

  const uint8_t* currentChar = (const uint8_t*) current;
  // remaining 1 to 63 bytes (standard algorithm)
  while (length-- != 0)
    crc = (crc >> 8) ^ Crc32Lookup[0][(crc & 0xFF) ^ *currentChar++];

  return ~crc; // same as crc ^ 0xFFFFFFFF
}

// Assembly:
movq %rdi, -0x8(%rsp)
movq %rsi, -0x10(%rsp)
movl %edx, -0x14(%rsp)
movq %rcx, -0x20(%rsp)
movl -0x14(%rsp), %eax
xorl $-0x1, %eax
movl %eax, -0x24(%rsp)
movq -0x8(%rsp), %rax
movq %rax, -0x30(%rsp)
movq $0x4, -0x38(%rsp)
movq $0x40, -0x40(%rsp)
movq -0x10(%rsp), %rax
movq -0x20(%rsp), %rcx
addq $0x40, %rcx
cmpq %rcx, %rax
jb 0x60e1c
movq -0x30(%rsp), %rax
addq -0x20(%rsp), %rax
prefetcht0 (%rax)
movq $0x0, -0x48(%rsp)
cmpq $0x4, -0x48(%rsp)
jae 0x60e09
movq -0x30(%rsp), %rax
movq %rax, %rcx
addq $0x4, %rcx
movq %rcx, -0x30(%rsp)
movl (%rax), %eax
xorl -0x24(%rsp), %eax
movl %eax, -0x4c(%rsp)
movq -0x30(%rsp), %rax
movq %rax, %rcx
addq $0x4, %rcx
movq %rcx, -0x30(%rsp)
movl (%rax), %eax
movl %eax, -0x50(%rsp)
movq -0x30(%rsp), %rax
movq %rax, %rcx
addq $0x4, %rcx
movq %rcx, -0x30(%rsp)
movl (%rax), %eax
movl %eax, -0x54(%rsp)
movq -0x30(%rsp), %rax
movq %rax, %rcx
addq $0x4, %rcx
movq %rcx, -0x30(%rsp)
movl (%rax), %eax
movl %eax, -0x58(%rsp)
movl -0x58(%rsp), %eax
shrl $0x18, %eax
andl $0xff, %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0x4ba6(%rip), %rax      # 0x657d0
movl (%rax,%rcx,4), %eax
movl -0x58(%rsp), %ecx
shrl $0x10, %ecx
andl $0xff, %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0x4b8b(%rip), %rcx      # 0x657d0
xorl 0x400(%rcx,%rdx,4), %eax
movl -0x58(%rsp), %ecx
shrl $0x8, %ecx
andl $0xff, %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0x4b6c(%rip), %rcx      # 0x657d0
xorl 0x800(%rcx,%rdx,4), %eax
movl -0x58(%rsp), %ecx
andl $0xff, %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0x4b50(%rip), %rcx      # 0x657d0
xorl 0xc00(%rcx,%rdx,4), %eax
movl -0x54(%rsp), %ecx
shrl $0x18, %ecx
andl $0xff, %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0x4b31(%rip), %rcx      # 0x657d0
xorl 0x1000(%rcx,%rdx,4), %eax
movl -0x54(%rsp), %ecx
shrl $0x10, %ecx
andl $0xff, %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0x4b12(%rip), %rcx      # 0x657d0
xorl 0x1400(%rcx,%rdx,4), %eax
movl -0x54(%rsp), %ecx
shrl $0x8, %ecx
andl $0xff, %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0x4af3(%rip), %rcx      # 0x657d0
xorl 0x1800(%rcx,%rdx,4), %eax
movl -0x54(%rsp), %ecx
andl $0xff, %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0x4ad7(%rip), %rcx      # 0x657d0
xorl 0x1c00(%rcx,%rdx,4), %eax
movl -0x50(%rsp), %ecx
shrl $0x18, %ecx
andl $0xff, %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0x4ab8(%rip), %rcx      # 0x657d0
xorl 0x2000(%rcx,%rdx,4), %eax
movl -0x50(%rsp), %ecx
shrl $0x10, %ecx
andl $0xff, %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0x4a99(%rip), %rcx      # 0x657d0
xorl 0x2400(%rcx,%rdx,4), %eax
movl -0x50(%rsp), %ecx
shrl $0x8, %ecx
andl $0xff, %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0x4a7a(%rip), %rcx      # 0x657d0
xorl 0x2800(%rcx,%rdx,4), %eax
movl -0x50(%rsp), %ecx
andl $0xff, %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0x4a5e(%rip), %rcx      # 0x657d0
xorl 0x2c00(%rcx,%rdx,4), %eax
movl -0x4c(%rsp), %ecx
shrl $0x18, %ecx
andl $0xff, %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0x4a3f(%rip), %rcx      # 0x657d0
xorl 0x3000(%rcx,%rdx,4), %eax
movl -0x4c(%rsp), %ecx
shrl $0x10, %ecx
andl $0xff, %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0x4a20(%rip), %rcx      # 0x657d0
xorl 0x3400(%rcx,%rdx,4), %eax
movl -0x4c(%rsp), %ecx
shrl $0x8, %ecx
andl $0xff, %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0x4a01(%rip), %rcx      # 0x657d0
xorl 0x3800(%rcx,%rdx,4), %eax
movl -0x4c(%rsp), %ecx
andl $0xff, %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0x49e5(%rip), %rcx      # 0x657d0
xorl 0x3c00(%rcx,%rdx,4), %eax
movl %eax, -0x24(%rsp)
movq -0x48(%rsp), %rax
addq $0x1, %rax
movq %rax, -0x48(%rsp)
jmp 0x60ba7
movq -0x10(%rsp), %rax
subq $0x40, %rax
movq %rax, -0x10(%rsp)
jmp 0x60b7a
movq -0x30(%rsp), %rax
movq %rax, -0x60(%rsp)
movq -0x10(%rsp), %rax
movq %rax, %rcx
addq $-0x1, %rcx
movq %rcx, -0x10(%rsp)
cmpq $0x0, %rax
je 0x60e78
movl -0x24(%rsp), %eax
shrl $0x8, %eax
movl -0x24(%rsp), %ecx
andl $0xff, %ecx
movq -0x60(%rsp), %rdx
movq %rdx, %rsi
addq $0x1, %rsi
movq %rsi, -0x60(%rsp)
movzbl (%rdx), %edx
xorl %edx, %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0x4961(%rip), %rcx      # 0x657d0
xorl (%rcx,%rdx,4), %eax
movl %eax, -0x24(%rsp)
jmp 0x60e26
movl -0x24(%rsp), %eax
xorl $-0x1, %eax
retq