// File: /workspace/github_c_makefile_star2_O1/dlbeer[P]dhara/ecc/hamming.c
// Function: parity_scan
static hamming_ecc_t parity_scan(const uint8_t *chunk, size_t len)
{
	uint8_t column = 0;
	uint16_t line = 0;
	uint16_t line_bar = 0;
	hamming_ecc_t out = 0;
	int i;

	/* Let the bits in chunk be partitioned into the following
	 * subsets:
	 *
	 *    P0 : bits  0,  2,  4,  6,  8, 10, 12, 14...
	 *    P0': bits  1,  3,  5,  7,  9, 11, 13, 15...
	 *    P1 : bits  0,  1,  4,  5,  8,  9, 12, 13...
	 *    P1': bits  2,  3,  6,  7, 10, 11, 14, 15...
	 *    P2 : bits  0,  1,  2,  3,  8,  9, 10, 11...
	 *    P2': bits  4,  5,  6,  7, 12, 13, 14, 15...
         *    P3 : bits  0,  1,  2,  3,  4,  5,  6,  7...
	 *    P3': bits  8,  9, 10, 11, 12, 13, 14, 15...
	 *
	 * That is, given a bit position i, and a pair of sets (Pm,
	 * Pm'), then i belongs to Pm if bit m in i is clear. Otherwise,
	 * it belongs to Pm'.
	 */
	for (i = 0; i < len; i++) {
		const uint8_t c = chunk[i];

		column ^= c;

		if (bit_count[c] & 1) {
			line ^= i;
			line_bar ^= ~i;
		}
	}

	/* The output checksum is the parity of the sets, in the
	 * following order:
	 *
	 *     ...P3', P3, P2', P2, P1', P1, P0', P0
	 *
	 * This is a linear code: the parity of the difference of two
	 * blocks is equal to the difference of their parities.
	 *
	 * If the bit at position i is flipped, then it flips the parity
	 * of exactly one of each pair of sets (position i belongs to
	 * one of each pair of sets).
	 *
	 * By observing which of each pair has changed parity, we can
	 * determine each bit of i.
	 */
	for (i = 0; i < HAMMING_LOG2_CHUNK_SIZE; i++) {
		out <<= 1;
		out |= (line_bar >> 8) & 1;

		out <<= 1;
		out |= (line >> 8) & 1;

		line <<= 1;
		line_bar <<= 1;
	}

	out = (out << 1) | (bit_count[column & 0x0f] & 1);
	out = (out << 1) | (bit_count[column & 0xf0] & 1);
	out = (out << 1) | (bit_count[column & 0x33] & 1);
	out = (out << 1) | (bit_count[column & 0xcc] & 1);
	out = (out << 1) | (bit_count[column & 0x55] & 1);
	out = (out << 1) | (bit_count[column & 0xaa] & 1);

	return out ^ 0xffffff;
}

// Assembly:
xorl %eax, %eax
testq %rsi, %rsi
je 0x11f1
pushq %rbp
pushq %rbx
xorl %r8d, %r8d
leaq 0xe5b(%rip), %r9        # 0x2010
xorl %r11d, %r11d
xorl %r10d, %r10d
xorl %edx, %edx
xorl %ecx, %ecx
movzbl (%rdi,%r11), %ebx
xorb %bl, %r10b
movl %edx, %ebp
xorl %r11d, %ebp
testb $0x1, (%rbx,%r9)
notl %ebp
movl %r11d, %ebx
cmovel %r8d, %ebx
cmovel %edx, %ebp
xorl %ebx, %ecx
movl %ebp, %edx
incq %r11
cmpq %r11, %rsi
jne 0x11bf
movzbl %r10b, %esi
popq %rbx
popq %rbp
jmp 0x11f7
xorl %ecx, %ecx
xorl %edx, %edx
xorl %esi, %esi
movl $0x9, %edi
movl %edx, %r8d
shrl $0x7, %r8d
andl $0x2, %r8d
leal (%r8,%rax,4), %r8d
movl %ecx, %eax
shrl $0x8, %eax
andl $0x1, %eax
orl %r8d, %eax
addl %ecx, %ecx
addl %edx, %edx
decl %edi
jne 0x11fc
movl %esi, %ecx
movl %ecx, %esi
andl $0xf, %esi
leaq 0xde4(%rip), %rdx       # 0x2010
movzbl (%rsi,%rdx), %esi
andl $0x1, %esi
addl %esi, %esi
leal (%rsi,%rax,4), %eax
movl %ecx, %esi
andl $-0x10, %esi
movzbl (%rsi,%rdx), %esi
andl $0x1, %esi
orl %eax, %esi
movl %ecx, %eax
andl $0x33, %eax
movzbl (%rax,%rdx), %eax
andl $0x1, %eax
addl %eax, %eax
leal (%rax,%rsi,4), %eax
movl %ecx, %esi
andl $-0x34, %esi
movzbl (%rsi,%rdx), %esi
andl $0x1, %esi
orl %eax, %esi
movl %ecx, %eax
andl $0x55, %eax
movzbl (%rax,%rdx), %eax
andl $0x1, %eax
addl %eax, %eax
leal (%rax,%rsi,4), %esi
andl $-0x56, %ecx
movzbl (%rcx,%rdx), %eax
andl $0x1, %eax
orl %esi, %eax
xorl $0xffffff, %eax         # imm = 0xFFFFFF
retq