// File: /workspace/github_cpp_makefile_star2_O1/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 $0x838, %rsp            # imm = 0x838
movq %rdi, %rbx
movl 0x810(%rdi), %edi
cmpl $0x0, 0x1018(%rbx)
movq %rdi, -0x38(%rbp)
jle 0x9b35
movb (%rbx), %al
movb %al, -0x48(%rbp)
movq $0x0, -0x30(%rbp)
leaq 0x6842(%rip), %r14      # 0x10300
testl %edi, %edi
jle 0x9b1e
movq -0x30(%rbp), %rax
movq 0x818(%rbx,%rax,8), %rax
movq (%rax), %rcx
movq %rcx, -0x40(%rbp)
movb 0x8(%rax), %r15b
movl %r15d, %eax
xorb -0x48(%rbp), %al
movzbl %al, %r12d
xorl %r13d, %r13d
movq 0x10(%rbx,%r13,8), %rax
movq (%rax), %rdi
movb 0x8(%rax), %al
xorb %r15b, %al
movzbl %al, %eax
shll $0x8, %eax
orq %r12, %rax
movzbl 0x12000(%r14,%rax), %esi
movl 0x8(%rbx), %ecx
movq -0x40(%rbp), %rdx
callq 0xa88d
movq -0x38(%rbp), %rdi
incq %r13
cmpq %r13, %rdi
jne 0x9ae6
movq -0x30(%rbp), %rsi
incq %rsi
movslq 0x1018(%rbx), %rax
movq %rsi, -0x30(%rbp)
cmpq %rax, %rsi
jl 0x9abe
movslq %edi, %r13
movl %edi, %eax
imull %edi, %eax
cmpl $0x800, %eax            # imm = 0x800
jbe 0x9b58
movl %eax, %edi
callq 0x2030
movq -0x38(%rbp), %rdi
movq %rax, %rcx
movq %rax, -0x50(%rbp)
jmp 0x9b67
leaq -0x860(%rbp), %rcx
movq $0x0, -0x50(%rbp)
leal -0x1(%rdi), %r14d
movl %r14d, %eax
imull %edi, %eax
movq %rdi, %r12
movl %eax, %edx
shrl $0x1f, %edx
addl %eax, %edx
sarl %edx
movslq %edx, %rdx
addq %rcx, %rdx
addq %rdx, %r13
movq %rbx, %rdi
movq %r13, %rsi
movq %rdx, -0x60(%rbp)
movq %rcx, -0x58(%rbp)
callq 0x967e
movl %r14d, %eax
movq %rax, -0x30(%rbp)
cmpl $0x2, %r12d
jl 0x9c0b
leaq 0x18(%rbx), %rdx
movq -0x38(%rbp), %rax
leaq -0x1(%rax), %r15
xorl %edi, %edi
movq 0x10(%rbx,%rdi,8), %rax
movq (%rax), %rax
movq %rax, -0x40(%rbp)
incq %rdi
movq %rdi, -0x48(%rbp)
xorl %r12d, %r12d
movq (%rdx,%r12,8), %rax
movq (%rax), %rdi
movzbl (%r13,%r12), %esi
movl 0x8(%rbx), %ecx
movq %rbx, %r14
movq %rdx, %rbx
movq -0x40(%rbp), %rdx
callq 0xa88d
movq %rbx, %rdx
movq %r14, %rbx
incq %r12
cmpq %r12, %r15
jne 0x9bca
addq $0x8, %rdx
decq %r15
addq %r12, %r13
movq -0x48(%rbp), %rdi
cmpq -0x30(%rbp), %rdi
jne 0x9bb4
movq -0x38(%rbp), %rcx
testl %ecx, %ecx
movq -0x60(%rbp), %r13
movq -0x58(%rbp), %r15
jle 0x9c68
xorl %r14d, %r14d
leaq 0x66db(%rip), %r12      # 0x10300
movq 0x10(%rbx,%r14,8), %rax
movq (%rax), %rdi
movb 0x101c(%rbx,%r14), %cl
movb %cl, 0x8(%rax)
movzbl (%r13,%r14), %ecx
movb $0x1, %al
cmpq $0x1, %rcx
je 0x9c4e
movb 0x22000(%r12,%rcx), %al
movl 0x8(%rbx), %ecx
movzbl %al, %edx
movq %rdi, %rsi
callq 0xa6ad
incq %r14
movq -0x38(%rbp), %rcx
cmpq %r14, %rcx
jne 0x9c25
cmpl $0x2, %ecx
movq -0x30(%rbp), %rax
jl 0x9cd0
leaq -0x1(%rax), %r13
movq %rax, -0x30(%rbp)
movq 0x10(%rbx,%rax,8), %rax
movq (%rax), %r12
movq %r13, -0x40(%rbp)
movq %rcx, -0x38(%rbp)
movl %ecx, %r14d
movl %r13d, %eax
movq 0x10(%rbx,%rax,8), %rax
movq (%rax), %rdi
movzbl (%r15), %esi
incq %r15
movl 0x8(%rbx), %ecx
movq %r12, %rdx
callq 0xa88d
decl %r14d
decq %r13
cmpl $0x1, %r14d
jg 0x9c8c
movq -0x30(%rbp), %rdx
leaq -0x1(%rdx), %rax
movq -0x38(%rbp), %rcx
decl %ecx
movq -0x40(%rbp), %r13
decq %r13
cmpq $0x1, %rdx
jg 0x9c75
movq -0x50(%rbp), %rdi
testq %rdi, %rdi
je 0x9cde
callq 0x2330
addq $0x838, %rsp            # imm = 0x838
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq