// File: sgielen[P]clife/./xxhash/xxhash.h
// Function: XXH3_accumulate_512_sse2(void*, void const*, void const*)
XXH_FORCE_INLINE XXH_TARGET_SSE2 void
XXH3_accumulate_512_sse2( void* XXH_RESTRICT acc,
                    const void* XXH_RESTRICT input,
                    const void* XXH_RESTRICT secret)
{
    /* SSE2 is just a half-scale version of the AVX2 version. */
    XXH_ASSERT((((size_t)acc) & 15) == 0);
    {   __m128i* const xacc    =       (__m128i *) acc;
        /* Unaligned. This is mainly for pointer arithmetic, and because
         * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */
        const         __m128i* const xinput  = (const __m128i *) input;
        /* Unaligned. This is mainly for pointer arithmetic, and because
         * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */
        const         __m128i* const xsecret = (const __m128i *) secret;

        size_t i;
        for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) {
            /* data_vec    = xinput[i]; */
            __m128i const data_vec    = _mm_loadu_si128   (xinput+i);
            /* key_vec     = xsecret[i]; */
            __m128i const key_vec     = _mm_loadu_si128   (xsecret+i);
            /* data_key    = data_vec ^ key_vec; */
            __m128i const data_key    = _mm_xor_si128     (data_vec, key_vec);
            /* data_key_lo = data_key >> 32; */
            __m128i const data_key_lo = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1));
            /* product     = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */
            __m128i const product     = _mm_mul_epu32     (data_key, data_key_lo);
            /* xacc[i] += swap(data_vec); */
            __m128i const data_swap = _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2));
            __m128i const sum       = _mm_add_epi64(xacc[i], data_swap);
            /* xacc[i] += product; */
            xacc[i] = _mm_add_epi64(product, sum);
    }   }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xc0, %rsp
movq %rdi, -0x98(%rbp)
movq %rsi, -0xa0(%rbp)
movq %rdx, -0xa8(%rbp)
movq -0x98(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq -0xa0(%rbp), %rax
movq %rax, -0xb8(%rbp)
movq -0xa8(%rbp), %rax
movq %rax, -0xc0(%rbp)
movq $0x0, -0xc8(%rbp)
cmpq $0x4, -0xc8(%rbp)
jae 0x45c1
movq -0xb8(%rbp), %rax
movq -0xc8(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
movups (%rax), %xmm0
movaps %xmm0, -0xe0(%rbp)
movq -0xc0(%rbp), %rax
movq -0xc8(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq %rax, -0x50(%rbp)
movq -0x50(%rbp), %rax
movups (%rax), %xmm0
movaps %xmm0, -0xf0(%rbp)
movaps -0xe0(%rbp), %xmm1
movaps -0xf0(%rbp), %xmm0
movaps %xmm1, -0x30(%rbp)
movaps %xmm0, -0x40(%rbp)
movaps -0x30(%rbp), %xmm0
movaps -0x40(%rbp), %xmm1
pxor %xmm1, %xmm0
movaps %xmm0, -0x100(%rbp)
movaps -0x100(%rbp), %xmm0
pshufd $0x31, %xmm0, %xmm0     # xmm0 = xmm0[1,0,3,0]
movaps %xmm0, -0x110(%rbp)
movaps -0x100(%rbp), %xmm1
movaps -0x110(%rbp), %xmm0
movaps %xmm1, -0x10(%rbp)
movaps %xmm0, -0x20(%rbp)
movaps -0x10(%rbp), %xmm0
movaps -0x20(%rbp), %xmm1
pmuludq %xmm1, %xmm0
movaps %xmm0, -0x120(%rbp)
movaps -0xe0(%rbp), %xmm0
pshufd $0x4e, %xmm0, %xmm0     # xmm0 = xmm0[2,3,0,1]
movdqa %xmm0, -0x130(%rbp)
movq -0xb0(%rbp), %rax
movq -0xc8(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movdqa (%rax), %xmm1
movdqa -0x130(%rbp), %xmm0
movdqa %xmm1, -0x60(%rbp)
movdqa %xmm0, -0x70(%rbp)
movdqa -0x60(%rbp), %xmm0
paddq -0x70(%rbp), %xmm0
movdqa %xmm0, -0x140(%rbp)
movdqa -0x120(%rbp), %xmm1
movdqa -0x140(%rbp), %xmm0
movdqa %xmm1, -0x80(%rbp)
movdqa %xmm0, -0x90(%rbp)
movdqa -0x80(%rbp), %xmm0
paddq -0x90(%rbp), %xmm0
movq -0xb0(%rbp), %rax
movq -0xc8(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movdqa %xmm0, (%rax)
movq -0xc8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xc8(%rbp)
jmp 0x4455
addq $0xc0, %rsp
popq %rbp
retq
nopw (%rax,%rax)