// File: /workspace/github_cpp_makefile_star2_O2/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, %r13
cmpl $0x1, %r13d
jne 0x827a
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
movl %ecx, %r12d
cmpl %ecx, %r13d
jne 0x82bf
movq (%r15), %rsi
movq 0x10(%r15), %rdx
movq %rbx, %rdi
movl %r14d, %ecx
callq 0x9292
movslq %r12d, %r12
addq $0x20, %r15
pushq $0x2
popq %r13
cmpq %r12, %r13
jge 0x8340
movq (%r15), %rsi
movq %rbx, %rdi
movl %r14d, %edx
callq 0x90ec
incq %r13
addq $0x10, %r15
jmp 0x829f
movl %r12d, -0x2c(%rbp)
shll $0x8, %r12d
movzwl %r12w, %eax
movzbl %r13b, %ecx
orq %rax, %rcx
leaq 0x7017(%rip), %rax      # 0xf2f0
movzbl 0x12000(%rax,%rcx), %edx
movq (%r15), %rsi
movq %rbx, %rdi
movl %r14d, %ecx
callq 0x93b6
movq %r13, -0x38(%rbp)
movslq %r13d, %r12
addq $0x10, %r15
pushq $0x1
popq %r13
cmpq %r12, %r13
jge 0x8340
movl %r13d, %eax
xorl -0x38(%rbp), %eax
movl %r13d, %ecx
xorl -0x2c(%rbp), %ecx
shll $0x8, %ecx
movzwl %cx, %ecx
movzbl %al, %eax
orl %ecx, %eax
leaq 0x6fcf(%rip), %rcx      # 0xf2f0
movzbl 0x12000(%rcx,%rax), %esi
movq (%r15), %rdx
movq %rbx, %rdi
movl %r14d, %ecx
callq 0x958e
incq %r13
addq $0x10, %r15
jmp 0x82fe
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq