// File: Alcaro[P]bridges/arlib/crc32.cpp
// Function: crc32_pclmul(arrayview<unsigned char>, unsigned int)
__attribute__((target("pclmul")))
static uint32_t crc32_pclmul(arrayview<uint8_t> data, uint32_t crc)
{
	// 0x104c11db7 is the usual polynomial; it's 0xedb88320 with bits reversed, and a 1 prefixed
	// 0x82608edb and 0x1db710641 also represent the same polynomial; they're the above two with or without a trailing 1 bit
	
	__m128i state = _mm_cvtsi32_si128(~crc);
	__m128i* ptr = (__m128i*)data.ptr();
	size_t len = data.size();
	
	__m128i fold_neg128 = _mm_set_epi32(0, crc32_poly_exp(-128-64), 0, crc32_poly_exp(-128));
	__m128i fold_8   = _mm_set_epi32(0, crc32_poly_exp(  8-64), 0, crc32_poly_exp(8));
	__m128i fold_16  = _mm_set_epi32(0, crc32_poly_exp( 16-64), 0, crc32_poly_exp(16));
	__m128i fold_32  = _mm_set_epi32(0, crc32_poly_exp( 32-64), 0, crc32_poly_exp(32));
	__m128i fold_64  = _mm_set_epi32(0, crc32_poly_exp( 64-64), 0, crc32_poly_exp(64));
	__m128i fold_128 = _mm_set_epi32(0, crc32_poly_exp(128-64), 0, crc32_poly_exp(128));
	__m128i fold_256 = _mm_set_epi32(0, crc32_poly_exp(256-64), 0, crc32_poly_exp(256));
	__m128i fold_384 = _mm_set_epi32(0, crc32_poly_exp(384-64), 0, crc32_poly_exp(384));
	__m128i fold_512 = _mm_set_epi32(0, crc32_poly_exp(512-64), 0, crc32_poly_exp(512));
	
	if (len >= 16+48+16)
	{
		__m128i state0 = state;
		__m128i state1 = _mm_setzero_si128();
		__m128i state2 = _mm_setzero_si128();
		__m128i state3 = _mm_setzero_si128();
		
		while (len >= 64+48+16)
		{
			// standard recommendation is process 64 bytes at the time, pclmul's latency is about 7x its execution time
			state0 = do_fold(_mm_xor_si128(state0, _mm_loadu_si128(ptr++)), fold_512);
			state1 = do_fold(_mm_xor_si128(state1, _mm_loadu_si128(ptr++)), fold_512);
			state2 = do_fold(_mm_xor_si128(state2, _mm_loadu_si128(ptr++)), fold_512);
			state3 = do_fold(_mm_xor_si128(state3, _mm_loadu_si128(ptr++)), fold_512);
			len -= 64;
		}
		
		state0 = do_fold(_mm_xor_si128(state0, _mm_loadu_si128(ptr++)), fold_384);
		state1 = do_fold(_mm_xor_si128(state1, _mm_loadu_si128(ptr++)), fold_256);
		state2 = do_fold(_mm_xor_si128(state2, _mm_loadu_si128(ptr++)), fold_128);
		
		state = _mm_xor_si128(_mm_xor_si128(state0, state1), _mm_xor_si128(state2, state3));
		len -= 48;
	}
	
	while (len >= 16+16)
	{
		state = do_fold(_mm_xor_si128(state, _mm_loadu_si128(ptr++)), fold_128);
		len -= 16;
	}
	
	
	const uint8_t * ptr8 = (uint8_t*)ptr;
	if (len & 8)
	{
		state = do_fold(_mm_xor_si128(state, _mm_loadl_epi64(ptr)), fold_64);
		ptr8 += 8;
	}
	if (len & 4)
	{
		state = do_fold(_mm_xor_si128(state, _mm_cvtsi32_si128(*(uint32_t*)ptr8)), fold_32);
		ptr8 += 4;
	}
	if (len & 2)
	{
		state = do_fold(_mm_xor_si128(state, _mm_cvtsi32_si128(*(uint16_t*)ptr8)), fold_16);
		ptr8 += 2;
	}
	if (len & 1)
	{
		state = do_fold(_mm_xor_si128(state, _mm_cvtsi32_si128(*(uint8_t*)ptr8)), fold_8);
		ptr8 += 1;
	}
	
	// alternative implementation, bigger and no meaningful perf difference
	//
	//__m128i folds[8] = {
	//	_mm_set_epi32(0, crc32_poly_exp(  0-64), 0, crc32_poly_exp(0)),
	//	_mm_set_epi32(0, crc32_poly_exp(  8-64), 0, crc32_poly_exp(8)),
	//	_mm_set_epi32(0, crc32_poly_exp( 16-64), 0, crc32_poly_exp(16)),
	//	_mm_set_epi32(0, crc32_poly_exp( 24-64), 0, crc32_poly_exp(24)),
	//	_mm_set_epi32(0, crc32_poly_exp( 32-64), 0, crc32_poly_exp(32)),
	//	_mm_set_epi32(0, crc32_poly_exp( 40-64), 0, crc32_poly_exp(40)),
	//	_mm_set_epi32(0, crc32_poly_exp( 48-64), 0, crc32_poly_exp(48)),
	//	_mm_set_epi32(0, crc32_poly_exp( 56-64), 0, crc32_poly_exp(56)),
	//};
	//
	//__attribute__((target("sse2")))
	//static forceinline __m128i load_sse2_small_highzero(const uint8_t * src, size_t len)
	//{
	//	static const uint8_t mask[32] = {
	//		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	//		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	//	};
	//	return _mm_and_si128(load_sse2_small_highundef(src, len), _mm_loadu_si128((__m128i*)(mask+16-len)));
	//}
	//
	//state = do_fold(_mm_xor_si128(state, load_sse2_small_highzero(ptr8, len&7)), folds[len&7]);
	//ptr8 += len&7;
	
	if (len >= 16)
		state = _mm_xor_si128(state, _mm_loadu_si128((__m128i*)ptr8));
	else
		state = do_fold(state, fold_neg128); // inverse fold - kinda funky, but it works. Used only if input size is less than 16.
	
	// fold 128 bits into 64
	__m128i mask_low32 = _mm_set1_epi64x(0x00000000FFFFFFFF);
	state = _mm_xor_si128(_mm_bsrli_si128(state, 8), _mm_clmulepi64_si128(state, fold_64, 0x00));
	state = _mm_xor_si128(_mm_bsrli_si128(state, 4), _mm_clmulepi64_si128(_mm_and_si128(state, mask_low32), fold_32, 0x00));
	
	// Barrett reduction, using P(x) and µ from http://intel.ly/2ySEwL0, with bits backwards
	// latter magic constant is the polynomial with an extra 1, but I have no idea what the former is
	// it's called U_PRIME in some other implementations, but that doesn't help me
	__m128i magic = _mm_set_epi64x(0x01f7011641, 0x01db710641);
	__m128i magic2;
	magic2 = _mm_clmulepi64_si128(_mm_and_si128(state,  mask_low32), magic, 0x10);
	magic2 = _mm_clmulepi64_si128(_mm_and_si128(magic2, mask_low32), magic, 0x00);
	
	return ~_mm_cvtsi128_si32(_mm_bsrli_si128(_mm_xor_si128(state, magic2), 4));
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xa20, %rsp            # imm = 0xA20
movq %rdi, -0x8b0(%rbp)
movq %rsi, -0x8a8(%rbp)
movl %edx, -0x8b4(%rbp)
movl -0x8b4(%rbp), %eax
notl %eax
movl %eax, -0x824(%rbp)
movd -0x824(%rbp), %xmm0
movaps %xmm0, -0x840(%rbp)
movaps -0x840(%rbp), %xmm0
movaps %xmm0, -0x8d0(%rbp)
leaq -0x8b0(%rbp), %rdi
movq %rdi, -0xa20(%rbp)
callq 0x62c0
movq -0xa20(%rbp), %rdi
movq %rax, -0x8d8(%rbp)
callq 0x6290
movq %rax, -0x8e0(%rbp)
movl $0xffffff40, %edi       # imm = 0xFFFFFF40
callq 0xdb40
movl %eax, -0xa18(%rbp)
movl $0xffffff80, %edi       # imm = 0xFFFFFF80
callq 0xdb40
movl -0xa18(%rbp), %ecx
movl $0x0, -0x704(%rbp)
movl %ecx, -0x708(%rbp)
movl $0x0, -0x70c(%rbp)
movl %eax, -0x710(%rbp)
movd -0x704(%rbp), %xmm0
movd -0x708(%rbp), %xmm1
punpckldq %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
movd -0x70c(%rbp), %xmm2
movd -0x710(%rbp), %xmm0
punpckldq %xmm2, %xmm0    # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1]
punpcklqdq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0]
movaps %xmm0, -0x720(%rbp)
movaps -0x720(%rbp), %xmm0
movaps %xmm0, -0x8f0(%rbp)
movl $0xffffffc8, %edi       # imm = 0xFFFFFFC8
callq 0xdb40
movl %eax, -0xa14(%rbp)
movl $0x8, %edi
callq 0xdb40
movl -0xa14(%rbp), %ecx
movl $0x0, -0x724(%rbp)
movl %ecx, -0x728(%rbp)
movl $0x0, -0x72c(%rbp)
movl %eax, -0x730(%rbp)
movd -0x724(%rbp), %xmm0
movd -0x728(%rbp), %xmm1
punpckldq %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
movd -0x72c(%rbp), %xmm2
movd -0x730(%rbp), %xmm0
punpckldq %xmm2, %xmm0    # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1]
punpcklqdq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0]
movaps %xmm0, -0x740(%rbp)
movaps -0x740(%rbp), %xmm0
movaps %xmm0, -0x900(%rbp)
movl $0xffffffd0, %edi       # imm = 0xFFFFFFD0
callq 0xdb40
movl %eax, -0xa10(%rbp)
movl $0x10, %edi
callq 0xdb40
movl -0xa10(%rbp), %ecx
movl $0x0, -0x744(%rbp)
movl %ecx, -0x748(%rbp)
movl $0x0, -0x74c(%rbp)
movl %eax, -0x750(%rbp)
movd -0x744(%rbp), %xmm0
movd -0x748(%rbp), %xmm1
punpckldq %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
movd -0x74c(%rbp), %xmm2
movd -0x750(%rbp), %xmm0
punpckldq %xmm2, %xmm0    # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1]
punpcklqdq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0]
movaps %xmm0, -0x760(%rbp)
movaps -0x760(%rbp), %xmm0
movaps %xmm0, -0x910(%rbp)
movl $0xffffffe0, %edi       # imm = 0xFFFFFFE0
callq 0xdb40
movl %eax, -0xa0c(%rbp)
movl $0x20, %edi
callq 0xdb40
movl -0xa0c(%rbp), %ecx
movl $0x0, -0x764(%rbp)
movl %ecx, -0x768(%rbp)
movl $0x0, -0x76c(%rbp)
movl %eax, -0x770(%rbp)
movd -0x764(%rbp), %xmm0
movd -0x768(%rbp), %xmm1
punpckldq %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
movd -0x76c(%rbp), %xmm2
movd -0x770(%rbp), %xmm0
punpckldq %xmm2, %xmm0    # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1]
punpcklqdq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0]
movaps %xmm0, -0x780(%rbp)
movaps -0x780(%rbp), %xmm0
movaps %xmm0, -0x920(%rbp)
xorl %edi, %edi
callq 0xdb40
movl %eax, -0xa08(%rbp)
movl $0x40, %edi
movl %edi, -0xa04(%rbp)
callq 0xdb40
movl -0xa08(%rbp), %ecx
movl -0xa04(%rbp), %edi
movl $0x0, -0x784(%rbp)
movl %ecx, -0x788(%rbp)
movl $0x0, -0x78c(%rbp)
movl %eax, -0x790(%rbp)
movd -0x784(%rbp), %xmm0
movd -0x788(%rbp), %xmm1
punpckldq %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
movd -0x78c(%rbp), %xmm2
movd -0x790(%rbp), %xmm0
punpckldq %xmm2, %xmm0    # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1]
punpcklqdq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0]
movaps %xmm0, -0x7a0(%rbp)
movaps -0x7a0(%rbp), %xmm0
movaps %xmm0, -0x930(%rbp)
callq 0xdb40
movl %eax, -0xa00(%rbp)
movl $0x80, %edi
callq 0xdb40
movl -0xa00(%rbp), %ecx
movl $0x0, -0x7a4(%rbp)
movl %ecx, -0x7a8(%rbp)
movl $0x0, -0x7ac(%rbp)
movl %eax, -0x7b0(%rbp)
movd -0x7a4(%rbp), %xmm0
movd -0x7a8(%rbp), %xmm1
punpckldq %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
movd -0x7ac(%rbp), %xmm2
movd -0x7b0(%rbp), %xmm0
punpckldq %xmm2, %xmm0    # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1]
punpcklqdq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0]
movaps %xmm0, -0x7c0(%rbp)
movaps -0x7c0(%rbp), %xmm0
movaps %xmm0, -0x940(%rbp)
movl $0xc0, %edi
callq 0xdb40
movl %eax, -0x9fc(%rbp)
movl $0x100, %edi            # imm = 0x100
callq 0xdb40
movl -0x9fc(%rbp), %ecx
movl $0x0, -0x7c4(%rbp)
movl %ecx, -0x7c8(%rbp)
movl $0x0, -0x7cc(%rbp)
movl %eax, -0x7d0(%rbp)
movd -0x7c4(%rbp), %xmm0
movd -0x7c8(%rbp), %xmm1
punpckldq %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
movd -0x7cc(%rbp), %xmm2
movd -0x7d0(%rbp), %xmm0
punpckldq %xmm2, %xmm0    # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1]
punpcklqdq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0]
movaps %xmm0, -0x7e0(%rbp)
movaps -0x7e0(%rbp), %xmm0
movaps %xmm0, -0x950(%rbp)
movl $0x140, %edi            # imm = 0x140
callq 0xdb40
movl %eax, -0x9f8(%rbp)
movl $0x180, %edi            # imm = 0x180
callq 0xdb40
movl -0x9f8(%rbp), %ecx
movl $0x0, -0x7e4(%rbp)
movl %ecx, -0x7e8(%rbp)
movl $0x0, -0x7ec(%rbp)
movl %eax, -0x7f0(%rbp)
movd -0x7e4(%rbp), %xmm0
movd -0x7e8(%rbp), %xmm1
punpckldq %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
movd -0x7ec(%rbp), %xmm2
movd -0x7f0(%rbp), %xmm0
punpckldq %xmm2, %xmm0    # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1]
punpcklqdq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0]
movaps %xmm0, -0x800(%rbp)
movaps -0x800(%rbp), %xmm0
movaps %xmm0, -0x960(%rbp)
movl $0x1c0, %edi            # imm = 0x1C0
callq 0xdb40
movl %eax, -0x9f4(%rbp)
movl $0x200, %edi            # imm = 0x200
callq 0xdb40
movl -0x9f4(%rbp), %ecx
movl $0x0, -0x804(%rbp)
movl %ecx, -0x808(%rbp)
movl $0x0, -0x80c(%rbp)
movl %eax, -0x810(%rbp)
movd -0x804(%rbp), %xmm0
movd -0x808(%rbp), %xmm1
punpckldq %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
movd -0x80c(%rbp), %xmm2
movd -0x810(%rbp), %xmm0
punpckldq %xmm2, %xmm0    # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1]
punpcklqdq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0]
movdqa %xmm0, -0x820(%rbp)
movdqa -0x820(%rbp), %xmm0
movdqa %xmm0, -0x970(%rbp)
cmpq $0x50, -0x8e0(%rbp)
jb 0xd356
movaps -0x8d0(%rbp), %xmm0
movaps %xmm0, -0x980(%rbp)
xorps %xmm0, %xmm0
movaps %xmm0, -0x6e0(%rbp)
movaps -0x6e0(%rbp), %xmm1
movaps %xmm1, -0x990(%rbp)
movaps %xmm0, -0x6f0(%rbp)
movaps -0x6f0(%rbp), %xmm1
movaps %xmm1, -0x9a0(%rbp)
movaps %xmm0, -0x700(%rbp)
movdqa -0x700(%rbp), %xmm0
movdqa %xmm0, -0x9b0(%rbp)
cmpq $0x80, -0x8e0(%rbp)
jb 0xd08b
movdqa -0x980(%rbp), %xmm1
movq -0x8d8(%rbp), %rax
movq %rax, %rcx
addq $0x10, %rcx
movq %rcx, -0x8d8(%rbp)
movq %rax, -0xe8(%rbp)
movq -0xe8(%rbp), %rax
movdqu (%rax), %xmm0
movdqa %xmm1, -0x140(%rbp)
movdqa %xmm0, -0x150(%rbp)
movdqa -0x140(%rbp), %xmm1
pxor -0x150(%rbp), %xmm1
movdqa -0x970(%rbp), %xmm0
movdqa %xmm1, -0x540(%rbp)
movdqa %xmm0, -0x550(%rbp)
movdqa -0x540(%rbp), %xmm1
movdqa -0x550(%rbp), %xmm0
pclmulqdq $0x0, %xmm0, %xmm1
movdqa -0x540(%rbp), %xmm0
movdqa -0x550(%rbp), %xmm2
pclmulqdq $0x11, %xmm2, %xmm0
movdqa %xmm1, -0x520(%rbp)
movdqa %xmm0, -0x530(%rbp)
movdqa -0x520(%rbp), %xmm0
pxor -0x530(%rbp), %xmm0
movdqa %xmm0, -0x980(%rbp)
movdqa -0x990(%rbp), %xmm1
movq -0x8d8(%rbp), %rax
movq %rax, %rcx
addq $0x10, %rcx
movq %rcx, -0x8d8(%rbp)
movq %rax, -0xf0(%rbp)
movq -0xf0(%rbp), %rax
movdqu (%rax), %xmm0
movdqa %xmm1, -0x160(%rbp)
movdqa %xmm0, -0x170(%rbp)
movdqa -0x160(%rbp), %xmm1
pxor -0x170(%rbp), %xmm1
movdqa -0x970(%rbp), %xmm0
movdqa %xmm1, -0x560(%rbp)
movdqa %xmm0, -0x570(%rbp)
movdqa -0x560(%rbp), %xmm1
movdqa -0x570(%rbp), %xmm0
pclmulqdq $0x0, %xmm0, %xmm1
movdqa -0x560(%rbp), %xmm0
movdqa -0x570(%rbp), %xmm2
pclmulqdq $0x11, %xmm2, %xmm0
movdqa %xmm1, -0x500(%rbp)
movdqa %xmm0, -0x510(%rbp)
movdqa -0x500(%rbp), %xmm0
pxor -0x510(%rbp), %xmm0
movdqa %xmm0, -0x990(%rbp)
movdqa -0x9a0(%rbp), %xmm1
movq -0x8d8(%rbp), %rax
movq %rax, %rcx
addq $0x10, %rcx
movq %rcx, -0x8d8(%rbp)
movq %rax, -0xf8(%rbp)
movq -0xf8(%rbp), %rax
movdqu (%rax), %xmm0
movdqa %xmm1, -0x180(%rbp)
movdqa %xmm0, -0x190(%rbp)
movdqa -0x180(%rbp), %xmm1
pxor -0x190(%rbp), %xmm1
movdqa -0x970(%rbp), %xmm0
movdqa %xmm1, -0x580(%rbp)
movdqa %xmm0, -0x590(%rbp)
movdqa -0x580(%rbp), %xmm1
movdqa -0x590(%rbp), %xmm0
pclmulqdq $0x0, %xmm0, %xmm1
movdqa -0x580(%rbp), %xmm0
movdqa -0x590(%rbp), %xmm2
pclmulqdq $0x11, %xmm2, %xmm0
movdqa %xmm1, -0x4e0(%rbp)
movdqa %xmm0, -0x4f0(%rbp)
movdqa -0x4e0(%rbp), %xmm0
pxor -0x4f0(%rbp), %xmm0
movdqa %xmm0, -0x9a0(%rbp)
movdqa -0x9b0(%rbp), %xmm1
movq -0x8d8(%rbp), %rax
movq %rax, %rcx
addq $0x10, %rcx
movq %rcx, -0x8d8(%rbp)
movq %rax, -0x100(%rbp)
movq -0x100(%rbp), %rax
movdqu (%rax), %xmm0
movdqa %xmm1, -0x1a0(%rbp)
movdqa %xmm0, -0x1b0(%rbp)
movdqa -0x1a0(%rbp), %xmm1
pxor -0x1b0(%rbp), %xmm1
movdqa -0x970(%rbp), %xmm0
movdqa %xmm1, -0x5a0(%rbp)
movdqa %xmm0, -0x5b0(%rbp)
movdqa -0x5a0(%rbp), %xmm1
movdqa -0x5b0(%rbp), %xmm0
pclmulqdq $0x0, %xmm0, %xmm1
movdqa -0x5a0(%rbp), %xmm0
movdqa -0x5b0(%rbp), %xmm2
pclmulqdq $0x11, %xmm2, %xmm0
movdqa %xmm1, -0x4c0(%rbp)
movdqa %xmm0, -0x4d0(%rbp)
movdqa -0x4c0(%rbp), %xmm0
pxor -0x4d0(%rbp), %xmm0
movdqa %xmm0, -0x9b0(%rbp)
movq -0x8e0(%rbp), %rax
subq $0x40, %rax
movq %rax, -0x8e0(%rbp)
jmp 0xcd77
movdqa -0x980(%rbp), %xmm1
movq -0x8d8(%rbp), %rax
movq %rax, %rcx
addq $0x10, %rcx
movq %rcx, -0x8d8(%rbp)
movq %rax, -0x108(%rbp)
movq -0x108(%rbp), %rax
movdqu (%rax), %xmm0
movdqa %xmm1, -0x1c0(%rbp)
movdqa %xmm0, -0x1d0(%rbp)
movdqa -0x1c0(%rbp), %xmm1
pxor -0x1d0(%rbp), %xmm1
movdqa -0x960(%rbp), %xmm0
movdqa %xmm1, -0x5c0(%rbp)
movdqa %xmm0, -0x5d0(%rbp)
movdqa -0x5c0(%rbp), %xmm1
movdqa -0x5d0(%rbp), %xmm0
pclmulqdq $0x0, %xmm0, %xmm1
movdqa -0x5c0(%rbp), %xmm0
movdqa -0x5d0(%rbp), %xmm2
pclmulqdq $0x11, %xmm2, %xmm0
movdqa %xmm1, -0x4a0(%rbp)
movdqa %xmm0, -0x4b0(%rbp)
movdqa -0x4a0(%rbp), %xmm0
pxor -0x4b0(%rbp), %xmm0
movdqa %xmm0, -0x980(%rbp)
movdqa -0x990(%rbp), %xmm1
movq -0x8d8(%rbp), %rax
movq %rax, %rcx
addq $0x10, %rcx
movq %rcx, -0x8d8(%rbp)
movq %rax, -0x110(%rbp)
movq -0x110(%rbp), %rax
movdqu (%rax), %xmm0
movdqa %xmm1, -0x1e0(%rbp)
movdqa %xmm0, -0x1f0(%rbp)
movdqa -0x1e0(%rbp), %xmm1
pxor -0x1f0(%rbp), %xmm1
movdqa -0x950(%rbp), %xmm0
movdqa %xmm1, -0x5e0(%rbp)
movdqa %xmm0, -0x5f0(%rbp)
movdqa -0x5e0(%rbp), %xmm1
movdqa -0x5f0(%rbp), %xmm0
pclmulqdq $0x0, %xmm0, %xmm1
movdqa -0x5e0(%rbp), %xmm0
movdqa -0x5f0(%rbp), %xmm2
pclmulqdq $0x11, %xmm2, %xmm0
movdqa %xmm1, -0x480(%rbp)
movdqa %xmm0, -0x490(%rbp)
movdqa -0x480(%rbp), %xmm0
pxor -0x490(%rbp), %xmm0
movdqa %xmm0, -0x990(%rbp)
movdqa -0x9a0(%rbp), %xmm1
movq -0x8d8(%rbp), %rax
movq %rax, %rcx
addq $0x10, %rcx
movq %rcx, -0x8d8(%rbp)
movq %rax, -0x118(%rbp)
movq -0x118(%rbp), %rax
movdqu (%rax), %xmm0
movdqa %xmm1, -0x200(%rbp)
movdqa %xmm0, -0x210(%rbp)
movdqa -0x200(%rbp), %xmm1
pxor -0x210(%rbp), %xmm1
movdqa -0x940(%rbp), %xmm0
movdqa %xmm1, -0x600(%rbp)
movdqa %xmm0, -0x610(%rbp)
movdqa -0x600(%rbp), %xmm1
movdqa -0x610(%rbp), %xmm0
pclmulqdq $0x0, %xmm0, %xmm1
movdqa -0x600(%rbp), %xmm0
movdqa -0x610(%rbp), %xmm2
pclmulqdq $0x11, %xmm2, %xmm0
movdqa %xmm1, -0x460(%rbp)
movdqa %xmm0, -0x470(%rbp)
movdqa -0x460(%rbp), %xmm0
pxor -0x470(%rbp), %xmm0
movdqa %xmm0, -0x9a0(%rbp)
movdqa -0x980(%rbp), %xmm1
movdqa -0x990(%rbp), %xmm0
movdqa %xmm1, -0x220(%rbp)
movdqa %xmm0, -0x230(%rbp)
movdqa -0x220(%rbp), %xmm1
pxor -0x230(%rbp), %xmm1
movdqa -0x9a0(%rbp), %xmm2
movdqa -0x9b0(%rbp), %xmm0
movdqa %xmm2, -0x240(%rbp)
movdqa %xmm0, -0x250(%rbp)
movdqa -0x240(%rbp), %xmm0
pxor -0x250(%rbp), %xmm0
movdqa %xmm1, -0x260(%rbp)
movdqa %xmm0, -0x270(%rbp)
movdqa -0x260(%rbp), %xmm0
pxor -0x270(%rbp), %xmm0
movdqa %xmm0, -0x8d0(%rbp)
movq -0x8e0(%rbp), %rax
subq $0x30, %rax
movq %rax, -0x8e0(%rbp)
jmp 0xd358
cmpq $0x20, -0x8e0(%rbp)
jb 0xd438
movdqa -0x8d0(%rbp), %xmm1
movq -0x8d8(%rbp), %rax
movq %rax, %rcx
addq $0x10, %rcx
movq %rcx, -0x8d8(%rbp)
movq %rax, -0x120(%rbp)
movq -0x120(%rbp), %rax
movdqu (%rax), %xmm0
movdqa %xmm1, -0x280(%rbp)
movdqa %xmm0, -0x290(%rbp)
movdqa -0x280(%rbp), %xmm1
pxor -0x290(%rbp), %xmm1
movdqa -0x940(%rbp), %xmm0
movdqa %xmm1, -0x620(%rbp)
movdqa %xmm0, -0x630(%rbp)
movdqa -0x620(%rbp), %xmm1
movdqa -0x630(%rbp), %xmm0
pclmulqdq $0x0, %xmm0, %xmm1
movdqa -0x620(%rbp), %xmm0
movdqa -0x630(%rbp), %xmm2
pclmulqdq $0x11, %xmm2, %xmm0
movdqa %xmm1, -0x440(%rbp)
movdqa %xmm0, -0x450(%rbp)
movdqa -0x440(%rbp), %xmm0
pxor -0x450(%rbp), %xmm0
movdqa %xmm0, -0x8d0(%rbp)
movq -0x8e0(%rbp), %rax
subq $0x10, %rax
movq %rax, -0x8e0(%rbp)
jmp 0xd358
movq -0x8d8(%rbp), %rax
movq %rax, -0x9b8(%rbp)
movq -0x8e0(%rbp), %rax
andq $0x8, %rax
cmpq $0x0, %rax
je 0xd529
movaps -0x8d0(%rbp), %xmm1
movq -0x8d8(%rbp), %rax
movq %rax, -0xd0(%rbp)
movq -0xd0(%rbp), %rax
movq (%rax), %xmm0
movdqa %xmm0, -0xe0(%rbp)
movdqa -0xe0(%rbp), %xmm0
movdqa %xmm1, -0x2a0(%rbp)
movdqa %xmm0, -0x2b0(%rbp)
movdqa -0x2a0(%rbp), %xmm1
pxor -0x2b0(%rbp), %xmm1
movdqa -0x930(%rbp), %xmm0
movdqa %xmm1, -0x640(%rbp)
movdqa %xmm0, -0x650(%rbp)
movdqa -0x640(%rbp), %xmm1
movdqa -0x650(%rbp), %xmm0
pclmulqdq $0x0, %xmm0, %xmm1
movdqa -0x640(%rbp), %xmm0
movdqa -0x650(%rbp), %xmm2
pclmulqdq $0x11, %xmm2, %xmm0
movdqa %xmm1, -0x420(%rbp)
movdqa %xmm0, -0x430(%rbp)
movdqa -0x420(%rbp), %xmm0
pxor -0x430(%rbp), %xmm0
movdqa %xmm0, -0x8d0(%rbp)
movq -0x9b8(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x9b8(%rbp)
movq -0x8e0(%rbp), %rax
andq $0x4, %rax
cmpq $0x0, %rax
je 0xd60a
movaps -0x8d0(%rbp), %xmm1
movq -0x9b8(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x844(%rbp)
movd -0x844(%rbp), %xmm0
movdqa %xmm0, -0x860(%rbp)
movdqa -0x860(%rbp), %xmm0
movdqa %xmm1, -0x2c0(%rbp)
movdqa %xmm0, -0x2d0(%rbp)
movdqa -0x2c0(%rbp), %xmm1
pxor -0x2d0(%rbp), %xmm1
movdqa -0x920(%rbp), %xmm0
movdqa %xmm1, -0x660(%rbp)
movdqa %xmm0, -0x670(%rbp)
movdqa -0x660(%rbp), %xmm1
movdqa -0x670(%rbp), %xmm0
pclmulqdq $0x0, %xmm0, %xmm1
movdqa -0x660(%rbp), %xmm0
movdqa -0x670(%rbp), %xmm2
pclmulqdq $0x11, %xmm2, %xmm0
movdqa %xmm1, -0x400(%rbp)
movdqa %xmm0, -0x410(%rbp)
movdqa -0x400(%rbp), %xmm0
pxor -0x410(%rbp), %xmm0
movdqa %xmm0, -0x8d0(%rbp)
movq -0x9b8(%rbp), %rax
addq $0x4, %rax
movq %rax, -0x9b8(%rbp)
movq -0x8e0(%rbp), %rax
andq $0x2, %rax
cmpq $0x0, %rax
je 0xd6ec
movaps -0x8d0(%rbp), %xmm1
movq -0x9b8(%rbp), %rax
movzwl (%rax), %eax
movl %eax, -0x864(%rbp)
movd -0x864(%rbp), %xmm0
movdqa %xmm0, -0x880(%rbp)
movdqa -0x880(%rbp), %xmm0
movdqa %xmm1, -0x2e0(%rbp)
movdqa %xmm0, -0x2f0(%rbp)
movdqa -0x2e0(%rbp), %xmm1
pxor -0x2f0(%rbp), %xmm1
movdqa -0x910(%rbp), %xmm0
movdqa %xmm1, -0x680(%rbp)
movdqa %xmm0, -0x690(%rbp)
movdqa -0x680(%rbp), %xmm1
movdqa -0x690(%rbp), %xmm0
pclmulqdq $0x0, %xmm0, %xmm1
movdqa -0x680(%rbp), %xmm0
movdqa -0x690(%rbp), %xmm2
pclmulqdq $0x11, %xmm2, %xmm0
movdqa %xmm1, -0x3e0(%rbp)
movdqa %xmm0, -0x3f0(%rbp)
movdqa -0x3e0(%rbp), %xmm0
pxor -0x3f0(%rbp), %xmm0
movdqa %xmm0, -0x8d0(%rbp)
movq -0x9b8(%rbp), %rax
addq $0x2, %rax
movq %rax, -0x9b8(%rbp)
movq -0x8e0(%rbp), %rax
andq $0x1, %rax
cmpq $0x0, %rax
je 0xd7ce
movaps -0x8d0(%rbp), %xmm1
movq -0x9b8(%rbp), %rax
movzbl (%rax), %eax
movl %eax, -0x884(%rbp)
movd -0x884(%rbp), %xmm0
movdqa %xmm0, -0x8a0(%rbp)
movdqa -0x8a0(%rbp), %xmm0
movdqa %xmm1, -0x300(%rbp)
movdqa %xmm0, -0x310(%rbp)
movdqa -0x300(%rbp), %xmm1
pxor -0x310(%rbp), %xmm1
movdqa -0x900(%rbp), %xmm0
movdqa %xmm1, -0x6a0(%rbp)
movdqa %xmm0, -0x6b0(%rbp)
movdqa -0x6a0(%rbp), %xmm1
movdqa -0x6b0(%rbp), %xmm0
pclmulqdq $0x0, %xmm0, %xmm1
movdqa -0x6a0(%rbp), %xmm0
movdqa -0x6b0(%rbp), %xmm2
pclmulqdq $0x11, %xmm2, %xmm0
movdqa %xmm1, -0x3c0(%rbp)
movdqa %xmm0, -0x3d0(%rbp)
movdqa -0x3c0(%rbp), %xmm0
pxor -0x3d0(%rbp), %xmm0
movdqa %xmm0, -0x8d0(%rbp)
movq -0x9b8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x9b8(%rbp)
cmpq $0x10, -0x8e0(%rbp)
jb 0xd823
movdqa -0x8d0(%rbp), %xmm1
movq -0x9b8(%rbp), %rax
movq %rax, -0x128(%rbp)
movq -0x128(%rbp), %rax
movdqu (%rax), %xmm0
movdqa %xmm1, -0x320(%rbp)
movdqa %xmm0, -0x330(%rbp)
movdqa -0x320(%rbp), %xmm0
pxor -0x330(%rbp), %xmm0
movdqa %xmm0, -0x8d0(%rbp)
jmp 0xd897
movdqa -0x8d0(%rbp), %xmm1
movdqa -0x8f0(%rbp), %xmm0
movdqa %xmm1, -0x6c0(%rbp)
movdqa %xmm0, -0x6d0(%rbp)
movdqa -0x6c0(%rbp), %xmm1
movdqa -0x6d0(%rbp), %xmm0
pclmulqdq $0x0, %xmm0, %xmm1
movdqa -0x6c0(%rbp), %xmm0
movdqa -0x6d0(%rbp), %xmm2
pclmulqdq $0x11, %xmm2, %xmm0
movdqa %xmm1, -0x3a0(%rbp)
movdqa %xmm0, -0x3b0(%rbp)
movdqa -0x3a0(%rbp), %xmm0
pxor -0x3b0(%rbp), %xmm0
movdqa %xmm0, -0x8d0(%rbp)
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movq %rax, -0xc8(%rbp)
movq -0xc8(%rbp), %rax
movq %rax, -0x48(%rbp)
movq %rax, -0x50(%rbp)
movq -0x48(%rbp), %xmm1
movq -0x50(%rbp), %xmm0
punpcklqdq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0]
movaps %xmm0, -0x60(%rbp)
movaps -0x60(%rbp), %xmm0
movaps %xmm0, -0x9d0(%rbp)
movaps -0x8d0(%rbp), %xmm0
movaps %xmm0, %xmm1
psrldq $0x8, %xmm1             # xmm1 = xmm1[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero
movaps -0x930(%rbp), %xmm2
pclmulqdq $0x0, %xmm2, %xmm0
movaps %xmm1, -0x340(%rbp)
movaps %xmm0, -0x350(%rbp)
movaps -0x340(%rbp), %xmm0
movaps -0x350(%rbp), %xmm1
pxor %xmm1, %xmm0
movaps %xmm0, -0x8d0(%rbp)
movaps -0x8d0(%rbp), %xmm2
movaps %xmm2, %xmm1
psrldq $0x4, %xmm1             # xmm1 = xmm1[4,5,6,7,8,9,10,11,12,13,14,15],zero,zero,zero,zero
movaps -0x9d0(%rbp), %xmm0
movaps %xmm2, -0x70(%rbp)
movaps %xmm0, -0x80(%rbp)
movaps -0x70(%rbp), %xmm0
movaps -0x80(%rbp), %xmm2
pand %xmm2, %xmm0
movaps -0x920(%rbp), %xmm2
pclmulqdq $0x0, %xmm2, %xmm0
movaps %xmm1, -0x360(%rbp)
movaps %xmm0, -0x370(%rbp)
movaps -0x360(%rbp), %xmm0
movaps -0x370(%rbp), %xmm1
pxor %xmm1, %xmm0
movaps %xmm0, -0x8d0(%rbp)
movabsq $0x1f7011641, %rax      # imm = 0x1F7011641
movq %rax, -0x28(%rbp)
movabsq $0x1db710641, %rax      # imm = 0x1DB710641
movq %rax, -0x30(%rbp)
movq -0x28(%rbp), %xmm1
movq -0x30(%rbp), %xmm0
punpcklqdq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0]
movaps %xmm0, -0x40(%rbp)
movaps -0x40(%rbp), %xmm0
movaps %xmm0, -0x9e0(%rbp)
movaps -0x8d0(%rbp), %xmm1
movaps -0x9d0(%rbp), %xmm0
movaps %xmm1, -0x90(%rbp)
movaps %xmm0, -0xa0(%rbp)
movaps -0x90(%rbp), %xmm0
movaps -0xa0(%rbp), %xmm1
pand %xmm1, %xmm0
movaps -0x9e0(%rbp), %xmm1
pclmulqdq $0x10, %xmm1, %xmm0
movaps %xmm0, -0x9f0(%rbp)
movaps -0x9f0(%rbp), %xmm1
movaps -0x9d0(%rbp), %xmm0
movaps %xmm1, -0xb0(%rbp)
movaps %xmm0, -0xc0(%rbp)
movaps -0xb0(%rbp), %xmm0
movaps -0xc0(%rbp), %xmm1
pand %xmm1, %xmm0
movaps -0x9e0(%rbp), %xmm1
pclmulqdq $0x0, %xmm1, %xmm0
movaps %xmm0, -0x9f0(%rbp)
movaps -0x8d0(%rbp), %xmm1
movaps -0x9f0(%rbp), %xmm0
movaps %xmm1, -0x380(%rbp)
movaps %xmm0, -0x390(%rbp)
movaps -0x380(%rbp), %xmm0
movaps -0x390(%rbp), %xmm1
pxor %xmm1, %xmm0
psrldq $0x4, %xmm0             # xmm0 = xmm0[4,5,6,7,8,9,10,11,12,13,14,15],zero,zero,zero,zero
movaps %xmm0, -0x10(%rbp)
movaps -0x10(%rbp), %xmm0
movaps %xmm0, -0x20(%rbp)
movl -0x20(%rbp), %eax
xorl $-0x1, %eax
addq $0xa20, %rsp            # imm = 0xA20
popq %rbp
retq
nopl (%rax,%rax)