// File: JMMackenzie[P]binary_to_jass/compress_integer_elias_gamma_simd.cpp
// Function: JASS::compress_integer_elias_gamma_simd::decode(unsigned int*, unsigned long, void const*, unsigned long)
void compress_integer_elias_gamma_simd::decode(integer *decoded, size_t integers_to_decode, const void *source_as_void, size_t source_length)
		{
		__m256i mask;
		const uint8_t *source = (const uint8_t *)source_as_void;
		const uint8_t *end_of_source = source + source_length;
		__m256i *into = (__m256i *)decoded;

		uint64_t selector = *(uint32_t *)source;
		__m256i payload1 = _mm256_loadu_si256((__m256i *)(source + 4));
		__m256i payload2 = _mm256_loadu_si256((__m256i *)(source + 36));
		source += 68;

		while (1)
			{
			uint32_t width = (uint32_t)find_first_set_bit(selector);
			mask = _mm256_loadu_si256((__m256i *)mask_set[width]);
			_mm256_storeu_si256(into, _mm256_and_si256(payload1, mask));
			_mm256_storeu_si256(into + 1, _mm256_and_si256(payload2, mask));
			payload1 = _mm256_srli_epi32(payload1, width);
			payload2 = _mm256_srli_epi32(payload2, width);

			into += 2;
			selector >>= width;

			while (selector == 0)
				{
				if (source >= end_of_source)
					return;

				/*
					Save the remaining bits
				*/
				__m256i high_bits1 = payload1;
				__m256i high_bits2 = payload2;

				/*
					move on to the next word
				*/
				selector = *(uint32_t *)source;
				payload1 = _mm256_loadu_si256((__m256i *)(source + 4));
				payload2 = _mm256_loadu_si256((__m256i *)(source + 36));
				source += 68;

				/*
					get the low bits and write to memory
				*/
				width = (uint32_t)find_first_set_bit(selector);

				high_bits1 = _mm256_slli_epi32(high_bits1, width);
				high_bits2 = _mm256_slli_epi32(high_bits2, width);

				mask = _mm256_loadu_si256((__m256i *)mask_set[width]);
				_mm256_storeu_si256(into, _mm256_or_si256(_mm256_and_si256(payload1, mask), high_bits1));
				_mm256_storeu_si256(into + 1, _mm256_or_si256(_mm256_and_si256(payload2, mask), high_bits2));
				payload1 = _mm256_srli_epi32(payload1, width);
				payload2 = _mm256_srli_epi32(payload2, width);

				/*
					move on to the next selctor
				*/
				into += 2;
				selector >>= width;
				}
			}
		}

// Assembly:
pushq %rbp
movq %rsp, %rbp
andq $-0x20, %rsp
subq $0x560, %rsp            # imm = 0x560
movq %rdi, 0x108(%rsp)
movq %rsi, 0x100(%rsp)
movq %rdx, 0xf8(%rsp)
movq %rcx, 0xf0(%rsp)
movq %r8, 0xe8(%rsp)
movq 0xf0(%rsp), %rax
movq %rax, 0xb8(%rsp)
movq 0xb8(%rsp), %rax
addq 0xe8(%rsp), %rax
movq %rax, 0xb0(%rsp)
movq 0x100(%rsp), %rax
movq %rax, 0xa8(%rsp)
movq 0xb8(%rsp), %rax
movl (%rax), %eax
movq %rax, 0xa0(%rsp)
movq 0xb8(%rsp), %rax
addq $0x4, %rax
movq %rax, 0x138(%rsp)
movq 0x138(%rsp), %rax
vmovdqu (%rax), %ymm0
vmovdqa %ymm0, 0x80(%rsp)
movq 0xb8(%rsp), %rax
addq $0x24, %rax
movq %rax, 0x130(%rsp)
movq 0x130(%rsp), %rax
vmovdqu (%rax), %ymm0
vmovdqa %ymm0, 0x60(%rsp)
movq 0xb8(%rsp), %rax
addq $0x44, %rax
movq %rax, 0xb8(%rsp)
movq 0xa0(%rsp), %rdi
vzeroupper
callq 0x300d60
movl %eax, 0x5c(%rsp)
movl 0x5c(%rsp), %eax
movl %eax, %ecx
leaq 0x336b(%rip), %rax      # 0x303bc0
shlq $0x6, %rcx
addq %rcx, %rax
movq %rax, 0x128(%rsp)
movq 0x128(%rsp), %rax
vmovdqu (%rax), %ymm0
vmovdqa %ymm0, 0xc0(%rsp)
movq 0xa8(%rsp), %rax
vmovdqa 0x80(%rsp), %ymm1
vmovdqa 0xc0(%rsp), %ymm0
vmovdqa %ymm1, 0x320(%rsp)
vmovdqa %ymm0, 0x300(%rsp)
vmovdqa 0x320(%rsp), %ymm0
vpand 0x300(%rsp), %ymm0, %ymm0
movq %rax, 0x238(%rsp)
vmovdqa %ymm0, 0x200(%rsp)
vmovdqa 0x200(%rsp), %ymm0
movq 0x238(%rsp), %rax
vmovdqu %ymm0, (%rax)
movq 0xa8(%rsp), %rax
addq $0x20, %rax
vmovdqa 0x60(%rsp), %ymm1
vmovdqa 0xc0(%rsp), %ymm0
vmovdqa %ymm1, 0x2e0(%rsp)
vmovdqa %ymm0, 0x2c0(%rsp)
vmovdqa 0x2e0(%rsp), %ymm0
vpand 0x2c0(%rsp), %ymm0, %ymm0
movq %rax, 0x1f8(%rsp)
vmovdqa %ymm0, 0x1c0(%rsp)
vmovdqa 0x1c0(%rsp), %ymm0
movq 0x1f8(%rsp), %rax
vmovdqu %ymm0, (%rax)
vmovdqa 0x80(%rsp), %ymm0
movl 0x5c(%rsp), %eax
vmovdqa %ymm0, 0x420(%rsp)
movl %eax, 0x41c(%rsp)
vmovdqa 0x420(%rsp), %ymm0
movl 0x41c(%rsp), %eax
vmovd %eax, %xmm1
vpsrld %xmm1, %ymm0, %ymm0
vmovdqa %ymm0, 0x80(%rsp)
vmovdqa 0x60(%rsp), %ymm0
movl 0x5c(%rsp), %eax
vmovdqa %ymm0, 0x3e0(%rsp)
movl %eax, 0x3dc(%rsp)
vmovdqa 0x3e0(%rsp), %ymm0
movl 0x3dc(%rsp), %eax
vmovd %eax, %xmm1
vpsrld %xmm1, %ymm0, %ymm0
vmovdqa %ymm0, 0x60(%rsp)
movq 0xa8(%rsp), %rax
addq $0x40, %rax
movq %rax, 0xa8(%rsp)
movl 0x5c(%rsp), %ecx
movq 0xa0(%rsp), %rax
movl %ecx, %ecx
shrq %cl, %rax
movq %rax, 0xa0(%rsp)
cmpq $0x0, 0xa0(%rsp)
jne 0x300d14
movq 0xb8(%rsp), %rax
cmpq 0xb0(%rsp), %rax
jb 0x300a0e
movq %rbp, %rsp
popq %rbp
vzeroupper
retq
vmovdqa 0x80(%rsp), %ymm0
vmovdqa %ymm0, 0x20(%rsp)
vmovdqa 0x60(%rsp), %ymm0
vmovdqa %ymm0, (%rsp)
movq 0xb8(%rsp), %rax
movl (%rax), %eax
movq %rax, 0xa0(%rsp)
movq 0xb8(%rsp), %rax
addq $0x4, %rax
movq %rax, 0x120(%rsp)
movq 0x120(%rsp), %rax
vmovdqu (%rax), %ymm0
vmovdqa %ymm0, 0x80(%rsp)
movq 0xb8(%rsp), %rax
addq $0x24, %rax
movq %rax, 0x118(%rsp)
movq 0x118(%rsp), %rax
vmovdqu (%rax), %ymm0
vmovdqa %ymm0, 0x60(%rsp)
movq 0xb8(%rsp), %rax
addq $0x44, %rax
movq %rax, 0xb8(%rsp)
movq 0xa0(%rsp), %rdi
vzeroupper
callq 0x300d60
movl %eax, 0x5c(%rsp)
vmovdqa 0x20(%rsp), %ymm0
movl 0x5c(%rsp), %eax
vmovdqa %ymm0, 0x4a0(%rsp)
movl %eax, 0x49c(%rsp)
vmovdqa 0x4a0(%rsp), %ymm0
movl 0x49c(%rsp), %eax
vmovd %eax, %xmm1
vpslld %xmm1, %ymm0, %ymm0
vmovdqa %ymm0, 0x20(%rsp)
vmovdqa (%rsp), %ymm0
movl 0x5c(%rsp), %eax
vmovdqa %ymm0, 0x460(%rsp)
movl %eax, 0x45c(%rsp)
vmovdqa 0x460(%rsp), %ymm0
movl 0x45c(%rsp), %eax
vmovd %eax, %xmm1
vpslld %xmm1, %ymm0, %ymm0
vmovdqa %ymm0, (%rsp)
movl 0x5c(%rsp), %eax
movl %eax, %ecx
leaq 0x3094(%rip), %rax      # 0x303bc0
shlq $0x6, %rcx
addq %rcx, %rax
movq %rax, 0x110(%rsp)
movq 0x110(%rsp), %rax
vmovdqu (%rax), %ymm0
vmovdqa %ymm0, 0xc0(%rsp)
movq 0xa8(%rsp), %rax
vmovdqa 0x80(%rsp), %ymm1
vmovdqa 0xc0(%rsp), %ymm0
vmovdqa %ymm1, 0x2a0(%rsp)
vmovdqa %ymm0, 0x280(%rsp)
vmovdqa 0x2a0(%rsp), %ymm0
vpand 0x280(%rsp), %ymm0, %ymm1
vmovdqa 0x20(%rsp), %ymm0
vmovdqa %ymm1, 0x520(%rsp)
vmovdqa %ymm0, 0x500(%rsp)
vmovdqa 0x520(%rsp), %ymm0
vpor 0x500(%rsp), %ymm0, %ymm0
movq %rax, 0x1b8(%rsp)
vmovdqa %ymm0, 0x180(%rsp)
vmovdqa 0x180(%rsp), %ymm0
movq 0x1b8(%rsp), %rax
vmovdqu %ymm0, (%rax)
movq 0xa8(%rsp), %rax
addq $0x20, %rax
vmovdqa 0x60(%rsp), %ymm1
vmovdqa 0xc0(%rsp), %ymm0
vmovdqa %ymm1, 0x260(%rsp)
vmovdqa %ymm0, 0x240(%rsp)
vmovdqa 0x260(%rsp), %ymm0
vpand 0x240(%rsp), %ymm0, %ymm1
vmovdqa (%rsp), %ymm0
vmovdqa %ymm1, 0x4e0(%rsp)
vmovdqa %ymm0, 0x4c0(%rsp)
vmovdqa 0x4e0(%rsp), %ymm0
vpor 0x4c0(%rsp), %ymm0, %ymm0
movq %rax, 0x178(%rsp)
vmovdqa %ymm0, 0x140(%rsp)
vmovdqa 0x140(%rsp), %ymm0
movq 0x178(%rsp), %rax
vmovdqu %ymm0, (%rax)
vmovdqa 0x80(%rsp), %ymm0
movl 0x5c(%rsp), %eax
vmovdqa %ymm0, 0x3a0(%rsp)
movl %eax, 0x39c(%rsp)
vmovdqa 0x3a0(%rsp), %ymm0
movl 0x39c(%rsp), %eax
vmovd %eax, %xmm1
vpsrld %xmm1, %ymm0, %ymm0
vmovdqa %ymm0, 0x80(%rsp)
vmovdqa 0x60(%rsp), %ymm0
movl 0x5c(%rsp), %eax
vmovdqa %ymm0, 0x360(%rsp)
movl %eax, 0x35c(%rsp)
vmovdqa 0x360(%rsp), %ymm0
movl 0x35c(%rsp), %eax
vmovd %eax, %xmm1
vpsrld %xmm1, %ymm0, %ymm0
vmovdqa %ymm0, 0x60(%rsp)
movq 0xa8(%rsp), %rax
addq $0x40, %rax
movq %rax, 0xa8(%rsp)
movl 0x5c(%rsp), %ecx
movq 0xa0(%rsp), %rax
movl %ecx, %ecx
shrq %cl, %rax
movq %rax, 0xa0(%rsp)
jmp 0x3009e5
jmp 0x300834
nopl (%rax)