// File: /workspace/github_cpp_makefile_star2_O1/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:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
notl %edx
leaq 0x40(%rcx), %rax
cmpq %rsi, %rax
ja 0x27c25
leaq 0x2c62(%rip), %r8       # 0x2a750
movl $0x3fc, %r9d            # imm = 0x3FC
movl $0xff, %r10d
prefetcht0 (%rdi,%rcx)
xorl %r11d, %r11d
xorl (%rdi,%r11), %edx
movl 0xc(%rdi,%r11), %ebx
movl %ebx, %r14d
shrl $0x18, %r14d
movl %ebx, %r15d
shrl $0xe, %r15d
andl %r9d, %r15d
movl %edx, %r12d
movl %edx, %r13d
movl %edx, %ebp
movl 0x400(%r15,%r8), %r15d
xorl (%r8,%r14,4), %r15d
movl %ebx, %r14d
shrl $0x8, %r14d
andl %r10d, %r14d
xorl 0x800(%r8,%r14,4), %r15d
movl 0x8(%rdi,%r11), %r14d
andl %r10d, %ebx
xorl 0xc00(%r8,%rbx,4), %r15d
movl %r14d, %ebx
shrl $0x18, %ebx
xorl 0x1000(%r8,%rbx,4), %r15d
movl %r14d, %ebx
shrl $0xe, %ebx
andl %r9d, %ebx
xorl 0x1400(%rbx,%r8), %r15d
movl %r14d, %ebx
shrl $0x8, %ebx
andl %r10d, %ebx
xorl 0x1800(%r8,%rbx,4), %r15d
movl 0x4(%rdi,%r11), %ebx
andl %r10d, %r14d
xorl 0x1c00(%r8,%r14,4), %r15d
movl %ebx, %r14d
shrl $0x18, %r14d
xorl 0x2000(%r8,%r14,4), %r15d
movl %ebx, %r14d
shrl $0xe, %r14d
andl %r9d, %r14d
xorl 0x2400(%r14,%r8), %r15d
movl %ebx, %r14d
shrl $0x8, %r14d
andl %r10d, %r14d
xorl 0x2800(%r8,%r14,4), %r15d
andl %r10d, %ebx
xorl 0x2c00(%r8,%rbx,4), %r15d
shrl $0x18, %edx
xorl 0x3000(%r8,%rdx,4), %r15d
shrl $0xe, %r12d
andl %r9d, %r12d
xorl 0x3400(%r12,%r8), %r15d
shrl $0x8, %r13d
andl %r10d, %r13d
xorl 0x3800(%r8,%r13,4), %r15d
andl %r10d, %ebp
movl %r15d, %edx
xorl 0x3c00(%r8,%rbp,4), %edx
addq $0x10, %r11
cmpq $0x40, %r11
jne 0x27b01
addq $0x40, %rdi
addq $-0x40, %rsi
cmpq %rax, %rsi
jae 0x27afa
testq %rsi, %rsi
je 0x27c53
xorl %ecx, %ecx
leaq 0x2b1d(%rip), %r8       # 0x2a750
movl %edx, %eax
shrl $0x8, %eax
movzbl %dl, %edx
movzbl (%rdi,%rcx), %r9d
xorl %edx, %r9d
xorl (%r8,%r9,4), %eax
incq %rcx
movl %eax, %edx
cmpq %rcx, %rsi
jne 0x27c35
jmp 0x27c55
movl %edx, %eax
notl %eax
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq