// File: 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
subq $0x920, %rsp            # imm = 0x920
movq %rdi, -0x30(%rbp)
movq -0x30(%rbp), %rax
movq %rax, -0x8f0(%rbp)
movl 0x810(%rax), %ecx
movl %ecx, -0x34(%rbp)
movl (%rax), %eax
movb %al, -0x35(%rbp)
movl $0x0, -0x3c(%rbp)
movq -0x8f0(%rbp), %rcx
movl -0x3c(%rbp), %eax
cmpl 0x1018(%rcx), %eax
jge 0xf970
movq -0x8f0(%rbp), %rax
movslq -0x3c(%rbp), %rcx
movq 0x818(%rax,%rcx,8), %rcx
movq (%rcx), %rcx
movq %rcx, -0x48(%rbp)
movslq -0x3c(%rbp), %rcx
movq 0x818(%rax,%rcx,8), %rax
movb 0x8(%rax), %al
movb %al, -0x49(%rbp)
movl $0x0, -0x50(%rbp)
movl -0x50(%rbp), %eax
cmpl -0x34(%rbp), %eax
jge 0xf960
movq -0x8f0(%rbp), %rcx
movslq -0x50(%rbp), %rax
movq 0x10(%rcx,%rax,8), %rax
movq (%rax), %rax
movq %rax, -0x58(%rbp)
movslq -0x50(%rbp), %rax
movq 0x10(%rcx,%rax,8), %rax
movb 0x8(%rax), %al
movb %al, -0x59(%rbp)
movb -0x49(%rbp), %al
movb %al, -0x5a(%rbp)
movb -0x59(%rbp), %sil
movb -0x35(%rbp), %dl
movb -0x5a(%rbp), %al
movb %sil, -0x1f(%rbp)
movb %dl, -0x20(%rbp)
movb %al, -0x21(%rbp)
movb -0x21(%rbp), %dl
movb -0x20(%rbp), %al
movb %dl, -0x1b(%rbp)
movb %al, -0x1c(%rbp)
movzbl -0x1b(%rbp), %eax
movzbl -0x1c(%rbp), %edx
xorl %edx, %eax
movb %al, %dl
movb -0x1f(%rbp), %sil
movb -0x21(%rbp), %al
movb %sil, -0x1d(%rbp)
movb %al, -0x1e(%rbp)
movzbl -0x1d(%rbp), %eax
movzbl -0x1e(%rbp), %esi
xorl %esi, %eax
movb %dl, -0x19(%rbp)
movb %al, -0x1a(%rbp)
movzbl -0x1a(%rbp), %eax
shll $0x8, %eax
movzbl -0x19(%rbp), %edx
addl %edx, %eax
movl %eax, %eax
movl %eax, %edx
leaq 0x8a5e(%rip), %rax      # 0x18390
movb 0x12000(%rax,%rdx), %al
movb %al, -0x5b(%rbp)
movq -0x58(%rbp), %rdi
movb -0x5b(%rbp), %al
movq -0x48(%rbp), %rdx
movl 0x8(%rcx), %ecx
movzbl %al, %esi
callq 0x11fe0
movl -0x50(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x50(%rbp)
jmp 0xf898
jmp 0xf962
movl -0x3c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x3c(%rbp)
jmp 0xf84f
movq $0x0, -0x868(%rbp)
leaq -0x860(%rbp), %rax
movq %rax, -0x870(%rbp)
movl -0x34(%rbp), %eax
imull -0x34(%rbp), %eax
movl %eax, -0x874(%rbp)
cmpl $0x800, -0x874(%rbp)    # imm = 0x800
jle 0xf9c3
movslq -0x874(%rbp), %rdi
callq 0x3030
movq %rax, -0x868(%rbp)
movq -0x868(%rbp), %rax
movq %rax, -0x870(%rbp)
movq -0x8f0(%rbp), %rdi
movq -0x870(%rbp), %rax
movq %rax, -0x880(%rbp)
movq -0x880(%rbp), %rax
movq %rax, -0x8f8(%rbp)
movl -0x34(%rbp), %eax
subl $0x1, %eax
imull -0x34(%rbp), %eax
movl $0x2, %ecx
cltd
idivl %ecx
movl %eax, %ecx
movq -0x8f8(%rbp), %rax
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0x888(%rbp)
movq -0x888(%rbp), %rax
movslq -0x34(%rbp), %rcx
addq %rcx, %rax
movq %rax, -0x890(%rbp)
movq -0x890(%rbp), %rsi
movq -0x888(%rbp), %rdx
movq -0x880(%rbp), %rcx
callq 0xef40
movl $0x0, -0x894(%rbp)
movl -0x894(%rbp), %eax
movl -0x34(%rbp), %ecx
subl $0x1, %ecx
cmpl %ecx, %eax
jge 0xfb12
movq -0x8f0(%rbp), %rax
movslq -0x894(%rbp), %rcx
movq 0x10(%rax,%rcx,8), %rax
movq (%rax), %rax
movq %rax, -0x8a0(%rbp)
movl -0x894(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x8a4(%rbp)
movl -0x8a4(%rbp), %eax
cmpl -0x34(%rbp), %eax
jge 0xfafc
movq -0x8f0(%rbp), %rcx
movslq -0x8a4(%rbp), %rax
movq 0x10(%rcx,%rax,8), %rax
movq (%rax), %rax
movq %rax, -0x8b0(%rbp)
movq -0x890(%rbp), %rax
movq %rax, %rdx
addq $0x1, %rdx
movq %rdx, -0x890(%rbp)
movb (%rax), %al
movb %al, -0x8b1(%rbp)
movq -0x8b0(%rbp), %rdi
movb -0x8b1(%rbp), %al
movq -0x8a0(%rbp), %rdx
movl 0x8(%rcx), %ecx
movzbl %al, %esi
callq 0x11fe0
movl -0x8a4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x8a4(%rbp)
jmp 0xfa87
jmp 0xfafe
movl -0x894(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x894(%rbp)
jmp 0xfa47
movl $0x0, -0x8b8(%rbp)
movl -0x8b8(%rbp), %eax
cmpl -0x34(%rbp), %eax
jge 0xfc0b
movq -0x8f0(%rbp), %rax
movslq -0x8b8(%rbp), %rcx
movq 0x10(%rax,%rcx,8), %rcx
movq (%rcx), %rcx
movq %rcx, -0x8c0(%rbp)
movslq -0x8b8(%rbp), %rcx
movb 0x101c(%rax,%rcx), %dl
movslq -0x8b8(%rbp), %rcx
movq 0x10(%rax,%rcx,8), %rcx
movb %dl, 0x8(%rcx)
movq -0x8c0(%rbp), %rsi
movq -0x8c0(%rbp), %rdx
movq -0x888(%rbp), %rcx
movslq -0x8b8(%rbp), %rdi
movb (%rcx,%rdi), %cl
movl 0x8(%rax), %eax
movq %rsi, -0x8(%rbp)
movq %rdx, -0x10(%rbp)
movb %cl, -0x11(%rbp)
movl %eax, -0x18(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x908(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x900(%rbp)
movzbl -0x11(%rbp), %eax
cmpl $0x1, %eax
jne 0xfbbe
movb $0x1, %al
movb %al, -0x909(%rbp)
jmp 0xfbd8
movzbl -0x11(%rbp), %eax
movl %eax, %ecx
leaq 0x87c5(%rip), %rax      # 0x18390
movb 0x22000(%rax,%rcx), %al
movb %al, -0x909(%rbp)
movq -0x900(%rbp), %rsi
movq -0x908(%rbp), %rdi
movb -0x909(%rbp), %al
movl -0x18(%rbp), %ecx
movzbl %al, %edx
callq 0x11890
movl -0x8b8(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x8b8(%rbp)
jmp 0xfb1c
movl -0x34(%rbp), %eax
subl $0x1, %eax
movl %eax, -0x8c4(%rbp)
cmpl $0x1, -0x8c4(%rbp)
jl 0xfcd9
movq -0x8f0(%rbp), %rax
movslq -0x8c4(%rbp), %rcx
movq 0x10(%rax,%rcx,8), %rax
movq (%rax), %rax
movq %rax, -0x8d0(%rbp)
movl -0x8c4(%rbp), %eax
subl $0x1, %eax
movl %eax, -0x8d4(%rbp)
cmpl $0x0, -0x8d4(%rbp)
jl 0xfcc3
movq -0x8f0(%rbp), %rcx
movslq -0x8d4(%rbp), %rax
movq 0x10(%rcx,%rax,8), %rax
movq (%rax), %rax
movq %rax, -0x8e0(%rbp)
movq -0x880(%rbp), %rax
movq %rax, %rdx
addq $0x1, %rdx
movq %rdx, -0x880(%rbp)
movb (%rax), %al
movb %al, -0x8e1(%rbp)
movq -0x8e0(%rbp), %rdi
movb -0x8e1(%rbp), %al
movq -0x8d0(%rbp), %rdx
movl 0x8(%rcx), %ecx
movzbl %al, %esi
callq 0x11fe0
movl -0x8d4(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x8d4(%rbp)
jmp 0xfc50
jmp 0xfcc5
movl -0x8c4(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x8c4(%rbp)
jmp 0xfc17
movq -0x868(%rbp), %rax
movq %rax, -0x918(%rbp)
cmpq $0x0, %rax
je 0xfcf9
movq -0x918(%rbp), %rdi
callq 0x3410
addq $0x920, %rsp            # imm = 0x920
popq %rbp
retq
nopw %cs:(%rax,%rax)