// File: /workspace/github_cpp_makefile_star2_O3/xocoder[P]m_kcptun/vendor/cm256/cm256.cpp
// Function: CM256Decoder::Decode()
void CM256Decoder::Decode()
{
    // Matrix size is NxN, where N is the number of recovery blocks used.
    const int N = RecoveryCount;

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

    // Eliminate original data from the the recovery rows
    for (int originalIndex = 0; originalIndex < OriginalCount; ++originalIndex)
    {
        const uint8_t* inBlock = static_cast<const uint8_t*>(Original[originalIndex]->Block);
        const uint8_t inRow = Original[originalIndex]->Index;

        for (int recoveryIndex = 0; recoveryIndex < N; ++recoveryIndex)
        {
            uint8_t* outBlock = static_cast<uint8_t*>(Recovery[recoveryIndex]->Block);
            const uint8_t x_i = Recovery[recoveryIndex]->Index;
            const uint8_t y_j = inRow;
            const uint8_t matrixElement = GetMatrixElement(x_i, x_0, y_j);

            gf256_muladd_mem(outBlock, matrixElement, inBlock, Params.BlockBytes);
        }
    }

    // Allocate matrix
    static const int StackAllocSize = 2048;
    uint8_t stackMatrix[StackAllocSize];
    uint8_t* dynamicMatrix = 0;
    uint8_t* matrix = stackMatrix;
    const int requiredSpace = N * N;
    if (requiredSpace > StackAllocSize)
    {
        dynamicMatrix = new uint8_t[requiredSpace];
        matrix = dynamicMatrix;
    }

    /*
        Compute matrix decomposition:

            G = L * D * U

        L is lower-triangular, diagonal is all ones.
        D is a diagonal matrix.
        U is upper-triangular, diagonal is all ones.
    */
    uint8_t* matrix_U = matrix;
    uint8_t* diag_D = matrix_U + (N - 1) * N / 2;
    uint8_t* matrix_L = diag_D + N;
    GenerateLDUDecomposition(matrix_L, diag_D, matrix_U);

    /*
        Eliminate lower left triangle.
    */
    // For each column,
    for (int j = 0; j < N - 1; ++j)
    {
        const void* block_j = Recovery[j]->Block;

        // For each row,
        for (int i = j + 1; i < N; ++i)
        {
            void* block_i = Recovery[i]->Block;
            const uint8_t c_ij = *matrix_L++; // Matrix elements are stored column-first, top-down.

            gf256_muladd_mem(block_i, c_ij, block_j, Params.BlockBytes);
        }
    }

    /*
        Eliminate diagonal.
    */
    for (int i = 0; i < N; ++i)
    {
        void* block = Recovery[i]->Block;

        Recovery[i]->Index = ErasuresIndices[i];

        gf256_div_mem(block, block, diag_D[i], Params.BlockBytes);
    }

    /*
        Eliminate upper right triangle.
    */
    for (int j = N - 1; j >= 1; --j)
    {
        const void* block_j = Recovery[j]->Block;

        for (int i = j - 1; i >= 0; --i)
        {
            void* block_i = Recovery[i]->Block;
            const uint8_t c_ij = *matrix_U++; // Matrix elements are stored column-first, bottom-up.

            gf256_muladd_mem(block_i, c_ij, block_j, Params.BlockBytes);
        }
    }

    delete[] dynamicMatrix;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x848, %rsp            # imm = 0x848
movq %rdi, %rbx
movl 0x810(%rdi), %r13d
movl 0x1018(%rdi), %eax
testl %eax, %eax
jle 0x9939
movb (%rbx), %cl
movb %cl, -0x50(%rbp)
xorl %edx, %edx
leaq 0x6a3e(%rip), %r15      # 0x10300
testl %r13d, %r13d
jle 0x992e
movq %rdx, -0x38(%rbp)
movq 0x818(%rbx,%rdx,8), %rax
movq (%rax), %rcx
movq %rcx, -0x40(%rbp)
movb 0x8(%rax), %al
movb %al, -0x30(%rbp)
xorb -0x50(%rbp), %al
movzbl %al, %r12d
movq %r13, %r14
xorl %r13d, %r13d
movq 0x10(%rbx,%r13,8), %rax
movq (%rax), %rdi
movb 0x8(%rax), %al
xorb -0x30(%rbp), %al
movzbl %al, %eax
shll $0x8, %eax
orq %r12, %rax
movzbl 0x12000(%r15,%rax), %esi
movl 0x8(%rbx), %ecx
movq -0x40(%rbp), %rdx
callq 0xa614
incq %r13
cmpq %r13, %r14
jne 0x98ed
movl 0x1018(%rbx), %eax
movq %r14, %r13
movq -0x38(%rbp), %rdx
incq %rdx
movslq %eax, %rcx
cmpq %rcx, %rdx
jl 0x98c2
movslq %r13d, %r14
movl %r13d, %eax
imull %r13d, %eax
cmpl $0x800, %eax            # imm = 0x800
jbe 0x995a
movl %eax, %edi
callq 0x2030
movq %rax, %rcx
movq %rax, -0x58(%rbp)
jmp 0x9969
leaq -0x870(%rbp), %rcx
movq $0x0, -0x58(%rbp)
leal -0x1(%r13), %eax
movl %eax, -0x44(%rbp)
imull %r13d, %eax
movl %eax, %edx
shrl $0x1f, %edx
addl %eax, %edx
sarl %edx
movslq %edx, %rdx
addq %rcx, %rdx
addq %rdx, %r14
movq %rbx, %rdi
movq %r14, %rsi
movq %rdx, -0x38(%rbp)
movq %rcx, -0x68(%rbp)
callq 0x9488
movq %r13, -0x30(%rbp)
cmpl $0x2, %r13d
jl 0x9a10
movq %r14, %rcx
movl -0x44(%rbp), %eax
movq %rax, -0x50(%rbp)
leaq 0x18(%rbx), %r12
movq -0x30(%rbp), %rax
leaq -0x1(%rax), %r15
xorl %edi, %edi
movq %rbx, -0x60(%rbp)
movq 0x10(%rbx,%rdi,8), %rax
movq (%rax), %r14
incq %rdi
movq %rdi, -0x40(%rbp)
xorl %ebx, %ebx
movq (%r12,%rbx,8), %rax
movq (%rax), %rdi
movq %rcx, %r13
movzbl (%rcx,%rbx), %esi
movq -0x60(%rbp), %rax
movl 0x8(%rax), %ecx
movq %r14, %rdx
callq 0xa614
movq %r13, %rcx
incq %rbx
cmpq %rbx, %r15
jne 0x99d0
addq $0x8, %r12
decq %r15
addq %rbx, %rcx
movq -0x40(%rbp), %rdi
cmpq -0x50(%rbp), %rdi
movq -0x60(%rbp), %rbx
jne 0x99bf
movq -0x30(%rbp), %r13
testl %r13d, %r13d
movq -0x68(%rbp), %r15
jle 0x9ad3
xorl %r14d, %r14d
leaq 0x68d5(%rip), %r12      # 0x10300
movq 0x10(%rbx,%r14,8), %rax
movq (%rax), %rdi
movb 0x101c(%rbx,%r14), %cl
movb %cl, 0x8(%rax)
movq -0x38(%rbp), %rax
movzbl (%rax,%r14), %ecx
movb $0x1, %al
cmpq $0x1, %rcx
je 0x9a57
movb 0x22000(%r12,%rcx), %al
movl 0x8(%rbx), %ecx
movzbl %al, %edx
movq %rdi, %rsi
callq 0xa41e
incq %r14
cmpq %r14, %r13
jne 0x9a2b
cmpl $0x2, %r13d
jl 0x9ad3
movl -0x44(%rbp), %eax
leaq -0x1(%rax), %r14
movq %rax, -0x38(%rbp)
movq 0x10(%rbx,%rax,8), %rax
movq (%rax), %r12
movq %r14, -0x40(%rbp)
movq %r13, -0x30(%rbp)
movl %r14d, %eax
movq 0x10(%rbx,%rax,8), %rax
movq (%rax), %rdi
movzbl (%r15), %esi
incq %r15
movl 0x8(%rbx), %ecx
movq %r12, %rdx
callq 0xa614
decl %r13d
decq %r14
cmpl $0x1, %r13d
jg 0x9a8e
movq -0x38(%rbp), %rcx
leaq -0x1(%rcx), %rax
movq -0x30(%rbp), %r13
decl %r13d
movq -0x40(%rbp), %r14
decq %r14
cmpq $0x1, %rcx
jg 0x9a7a
movq -0x58(%rbp), %rdi
testq %rdi, %rdi
je 0x9ae1
callq 0x2340
addq $0x848, %rsp            # imm = 0x848
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq