// File: /workspace/github_cpp_makefile_star2_O1/xocoder[P]m_kcptun/vendor/cm256/cm256.cpp
// Function: cm256_encode_block
void cm256_encode_block(
    cm256_encoder_params params, // Encoder parameters
    cm256_block* originals,      // Array of pointers to original blocks
    int recoveryBlockIndex,      // Return value from cm256_get_recovery_block_index()
    void* recoveryBlock)         // Output recovery block
{
    // If only one block of input data,
    if (params.OriginalCount == 1)
    {
        // No meaningful operation here, degenerate to outputting the same data each time.

        memcpy(recoveryBlock, originals[0].Block, params.BlockBytes);
        return;
    }
    // else OriginalCount >= 2:

    // Unroll first row of recovery matrix:
    // The matrix we generate for the first row is all ones,
    // so it is merely a parity of the original data.
    if (recoveryBlockIndex == params.OriginalCount)
    {
        gf256_addset_mem(recoveryBlock, originals[0].Block, originals[1].Block, params.BlockBytes);
        for (int j = 2; j < params.OriginalCount; ++j)
        {
            gf256_add_mem(recoveryBlock, originals[j].Block, params.BlockBytes);
        }
        return;
    }

    // TBD: Faster algorithms seem to exist for computing this matrix-vector product.

    // Start the x_0 values arbitrarily from the original count.
    const uint8_t x_0 = static_cast<uint8_t>(params.OriginalCount);

    // For other rows:
    {
        const uint8_t x_i = static_cast<uint8_t>(recoveryBlockIndex);

        // Unroll first operation for speed
        {
            const uint8_t y_0 = 0;
            const uint8_t matrixElement = GetMatrixElement(x_i, x_0, y_0);

            gf256_mul_mem(recoveryBlock, originals[0].Block, matrixElement, params.BlockBytes);
        }

        // For each original data column,
        for (int j = 1; j < params.OriginalCount; ++j)
        {
            const uint8_t y_j = static_cast<uint8_t>(j);
            const uint8_t matrixElement = GetMatrixElement(x_i, x_0, y_j);

            gf256_muladd_mem(recoveryBlock, matrixElement, originals[j].Block, params.BlockBytes);
        }
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movq %r8, %rbx
movq %rdx, %r15
movl %esi, %r14d
movq %rdi, %r12
cmpl $0x1, %r12d
jne 0x9386
movq (%r15), %rsi
movslq %r14d, %rdx
movq %rbx, %rdi
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2220
cmpl %ecx, %r12d
jne 0x93d2
movq (%r15), %rsi
movq 0x10(%r15), %rdx
movq %rbx, %rdi
movl %r14d, %ecx
callq 0xa5c0
cmpl $0x3, %r12d
jl 0x945e
andl $0x7fffffff, %r12d      # imm = 0x7FFFFFFF
addq $0x20, %r15
addq $-0x2, %r12
movq (%r15), %rsi
movq %rbx, %rdi
movl %r14d, %edx
callq 0xa45b
addq $0x10, %r15
decq %r12
jne 0x93b6
jmp 0x945e
movl %ecx, %eax
shll $0x8, %eax
movzwl %ax, %eax
movl %ecx, -0x2c(%rbp)
movzbl %r12b, %ecx
orq %rax, %rcx
leaq 0x6f15(%rip), %rax      # 0x10300
movzbl 0x12000(%rax,%rcx), %edx
movq (%r15), %rsi
movq %rbx, %rdi
movl %r14d, %ecx
callq 0xa6ad
cmpl $0x2, %r12d
jl 0x945e
movl %r12d, %eax
andl $0x7fffffff, %eax       # imm = 0x7FFFFFFF
movq %rax, -0x38(%rbp)
addq $0x10, %r15
movl $0x1, %r13d
movl %r13d, %eax
xorl %r12d, %eax
movl %r13d, %ecx
xorl -0x2c(%rbp), %ecx
shll $0x8, %ecx
movzwl %cx, %ecx
movzbl %al, %eax
orl %ecx, %eax
leaq 0x6ec5(%rip), %rcx      # 0x10300
movzbl 0x12000(%rcx,%rax), %esi
movq (%r15), %rdx
movq %rbx, %rdi
movl %r14d, %ecx
callq 0xa88d
incq %r13
addq $0x10, %r15
cmpq %r13, -0x38(%rbp)
jne 0x941d
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq