// File: /workspace/github_cpp_makefile_star2_O3/VanAndelInstitute[P]intent/src/edlib.cpp
// Function: myersCalcEditDistanceNW(unsigned long const*, int, int, int, unsigned char const*, int, int, int*, int*, bool, AlignmentData**, int)
static int myersCalcEditDistanceNW(const Word* const Peq, const int W, const int maxNumBlocks,
                                   const int queryLength,
                                   const unsigned char* const target, const int targetLength,
                                   int k, int* const bestScore_,
                                   int* const position_, const bool findAlignment,
                                   AlignmentData** const alignData, const int targetStopPosition) {
    if (targetStopPosition > -1 && findAlignment) {
        // They can not be both set at the same time!
        return EDLIB_STATUS_ERROR;
    }

    // Each STRONG_REDUCE_NUM column is reduced in more expensive way.
    const int STRONG_REDUCE_NUM = 2048; // TODO: Choose this number dinamically (based on query and target lengths?), so it does not affect speed of computation

    if (k < abs(targetLength - queryLength)) {
        *bestScore_ = *position_ = -1;
        return EDLIB_STATUS_OK;
    }

    k = min(k, max(queryLength, targetLength));  // Upper bound for k

    // firstBlock is 0-based index of first block in Ukkonen band.
    // lastBlock is 0-based index of last block in Ukkonen band.
    int firstBlock = 0;
    // This is optimal now, by my formula.
    int lastBlock = min(maxNumBlocks, ceilDiv(min(k, (k + queryLength - targetLength) / 2) + 1, WORD_SIZE)) - 1;
    Block* bl; // Current block

    Block* blocks = new Block[maxNumBlocks];

    // Initialize P, M and score
    bl = blocks;
    for (int b = 0; b <= lastBlock; b++) {
        bl->score = (b + 1) * WORD_SIZE;
        bl->P = static_cast<Word>(-1); // All 1s
        bl->M = static_cast<Word>(0);
        bl++;
    }

    // If we want to find alignment, we have to store needed data.
    if (findAlignment)
        *alignData = new AlignmentData(maxNumBlocks, targetLength);
    else if (targetStopPosition > -1)
        *alignData = new AlignmentData(maxNumBlocks, 1);
    else
        *alignData = NULL;

    const unsigned char* targetChar = target;
    for (int c = 0; c < targetLength; c++) { // for each column
        const Word* Peq_c = Peq + *targetChar * maxNumBlocks;

        //----------------------- Calculate column -------------------------//
        int hout = 1;
        bl = blocks + firstBlock;
        for (int b = firstBlock; b <= lastBlock; b++) {
            hout = calculateBlock(bl->P, bl->M, Peq_c[b], hout, bl->P, bl->M);
            bl->score += hout;
            bl++;
        }
        bl--;
        //------------------------------------------------------------------//
        // bl now points to last block

        // Update k. I do it only on end of column because it would slow calculation too much otherwise.
        // NOTICE: I add W when in last block because it is actually result from W cells to the left and W cells up.
        k = min(k, bl->score
                + max(targetLength - c - 1, queryLength - ((1 + lastBlock) * WORD_SIZE - 1) - 1)
                + (lastBlock == maxNumBlocks - 1 ? W : 0));

        //---------- Adjust number of blocks according to Ukkonen ----------//
        //--- Adjust last block ---//
        // If block is not beneath band, calculate next block. Only next because others are certainly beneath band.
        if (lastBlock + 1 < maxNumBlocks
            && !(//score[lastBlock] >= k + WORD_SIZE ||  // NOTICE: this condition could be satisfied if above block also!
                 ((lastBlock + 1) * WORD_SIZE - 1
                  > k - bl->score + 2 * WORD_SIZE - 2 - targetLength + c + queryLength))) {
            lastBlock++; bl++;
            bl->P = static_cast<Word>(-1); // All 1s
            bl->M = static_cast<Word>(0);
            int newHout = calculateBlock(bl->P, bl->M, Peq_c[lastBlock], hout, bl->P, bl->M);
            bl->score = (bl - 1)->score - hout + WORD_SIZE + newHout;
            hout = newHout;
        }

        // While block is out of band, move one block up.
        // NOTE: Condition used here is more loose than the one from the article, since I simplified the max() part of it.
        // I could consider adding that max part, for optimal performance.
        while (lastBlock >= firstBlock
               && (bl->score >= k + WORD_SIZE
                   || ((lastBlock + 1) * WORD_SIZE - 1 >
                       // TODO: Does not work if do not put +1! Why???
                       k - bl->score + 2 * WORD_SIZE - 2 - targetLength + c + queryLength + 1))) {
            lastBlock--; bl--;
        }
        //-------------------------//

        //--- Adjust first block ---//
        // While outside of band, advance block
        while (firstBlock <= lastBlock
               && (blocks[firstBlock].score >= k + WORD_SIZE
                   || ((firstBlock + 1) * WORD_SIZE - 1 <
                       blocks[firstBlock].score - k - targetLength + queryLength + c))) {
            firstBlock++;
        }
        //--------------------------/


        // TODO: consider if this part is useful, it does not seem to help much
        if (c % STRONG_REDUCE_NUM == 0) { // Every some columns do more expensive but more efficient reduction
            while (lastBlock >= firstBlock) {
                // If all cells outside of band, remove block
                vector<int> scores = getBlockCellValues(*bl);
                int numCells = lastBlock == maxNumBlocks - 1 ? WORD_SIZE - W : WORD_SIZE;
                int r = lastBlock * WORD_SIZE + numCells - 1;
                bool reduce = true;
                for (int i = WORD_SIZE - numCells; i < WORD_SIZE; i++) {
                    // TODO: Does not work if do not put +1! Why???
                    if (scores[i] <= k && r <= k - scores[i] - targetLength + c + queryLength + 1) {
                        reduce = false;
                        break;
                    }
                    r--;
                }
                if (!reduce) break;
                lastBlock--; bl--;
            }

            while (firstBlock <= lastBlock) {
                // If all cells outside of band, remove block
                vector<int> scores = getBlockCellValues(blocks[firstBlock]);
                int numCells = firstBlock == maxNumBlocks - 1 ? WORD_SIZE - W : WORD_SIZE;
                int r = firstBlock * WORD_SIZE + numCells - 1;
                bool reduce = true;
                for (int i = WORD_SIZE - numCells; i < WORD_SIZE; i++) {
                    if (scores[i] <= k && r >= scores[i] - k - targetLength + c + queryLength) {
                        reduce = false;
                        break;
                    }
                    r--;
                }
                if (!reduce) break;
                firstBlock++;
            }
        }


        // If band stops to exist finish
        if (lastBlock < firstBlock) {
            *bestScore_ = *position_ = -1;
            delete[] blocks;
            return EDLIB_STATUS_OK;
        }
        //------------------------------------------------------------------//


        //---- Save column so it can be used for reconstruction ----//
        if (findAlignment && c < targetLength) {
            bl = blocks + firstBlock;
            for (int b = firstBlock; b <= lastBlock; b++) {
                (*alignData)->Ps[maxNumBlocks * c + b] = bl->P;
                (*alignData)->Ms[maxNumBlocks * c + b] = bl->M;
                (*alignData)->scores[maxNumBlocks * c + b] = bl->score;
                (*alignData)->firstBlocks[c] = firstBlock;
                (*alignData)->lastBlocks[c] = lastBlock;
                bl++;
            }
        }
        //----------------------------------------------------------//
        //---- If this is stop column, save it and finish ----//
        if (c == targetStopPosition) {
            for (int b = firstBlock; b <= lastBlock; b++) {
                (*alignData)->Ps[b] = (blocks + b)->P;
                (*alignData)->Ms[b] = (blocks + b)->M;
                (*alignData)->scores[b] = (blocks + b)->score;
                (*alignData)->firstBlocks[0] = firstBlock;
                (*alignData)->lastBlocks[0] = lastBlock;
            }
            *bestScore_ = -1;
            *position_ = targetStopPosition;
            delete[] blocks;
            return EDLIB_STATUS_OK;
        }
        //----------------------------------------------------//

        targetChar++;
    }

    if (lastBlock == maxNumBlocks - 1) { // If last block of last column was calculated
        // Obtain best score from block -> it is complicated because query is padded with W cells
        int bestScore = getBlockCellValues(blocks[lastBlock])[W];
        if (bestScore <= k) {
            *bestScore_ = bestScore;
            *position_ = targetLength - 1;
            delete[] blocks;
            return EDLIB_STATUS_OK;
        }
    }

    *bestScore_ = *position_ = -1;
    delete[] blocks;
    return EDLIB_STATUS_OK;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xc8, %rsp
movl %ecx, %r13d
movq %rdx, 0x40(%rsp)
movl %esi, 0x30(%rsp)
movq %rdi, 0x88(%rsp)
movl 0x128(%rsp), %r14d
testl %r14d, %r14d
setns %cl
movl $0x1, %eax
testb %cl, 0x118(%rsp)
jne 0x2bfae
movl %r9d, %ebx
movq 0x110(%rsp), %rsi
movq 0x108(%rsp), %rdi
movl 0x100(%rsp), %eax
movl %r9d, %ecx
subl %r13d, %ecx
movl %ecx, %edx
negl %edx
cmovsl %ecx, %edx
cmpl %eax, %edx
jle 0x2b616
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movl %eax, (%rsi)
movl %eax, (%rdi)
jmp 0x2bfac
movq %r8, %r12
movl %r13d, %ecx
subl %ebx, %ecx
movl %ebx, %edx
cmovgl %r13d, %edx
cmpl %edx, %eax
cmovll %eax, %edx
movq %rcx, 0x60(%rsp)
addl %edx, %ecx
movl %ecx, %eax
shrl $0x1f, %eax
addl %ecx, %eax
sarl %eax
cmpl %eax, %edx
movq %rdx, 0x18(%rsp)
cmovll %edx, %eax
incl %eax
testb $0x3f, %al
je 0x2b65c
leal 0x3f(%rax), %r15d
testl %eax, %eax
cmovnsl %eax, %r15d
sarl $0x6, %r15d
incl %r15d
jmp 0x2b662
sarl $0x6, %eax
movl %eax, %r15d
movq 0x40(%rsp), %rax
cmpl %r15d, %eax
cmovll %eax, %r15d
cltq
movl $0x18, %ecx
movq %rax, 0x80(%rsp)
mulq %rcx
movq $-0x1, %rdi
cmovnoq %rax, %rdi
callq 0x6030
movq %rax, 0x10(%rsp)
testl %r15d, %r15d
jle 0x2b6c8
movq 0x10(%rsp), %rax
addq $0x10, %rax
movl $0x40, %ecx
movl %r15d, %edx
movl %ecx, (%rax)
movq $-0x1, -0x10(%rax)
movq $0x0, -0x8(%rax)
addl $0x40, %ecx
addq $0x18, %rax
decl %edx
jne 0x2b6ab
cmpb $0x0, 0x118(%rsp)
movq %rbx, 0x28(%rsp)
movq %r13, 0x58(%rsp)
movq %r12, 0x20(%rsp)
je 0x2b6ff
movl $0x28, %edi
callq 0x63b0
movq %rax, %rbp
movq %rax, %rdi
movq 0x40(%rsp), %rsi
movl %ebx, %edx
callq 0x2dca8
jmp 0x2b727
testl %r14d, %r14d
js 0x2b725
movl $0x28, %edi
callq 0x63b0
movq %rax, %rbp
movq %rax, %rdi
movq 0x40(%rsp), %rsi
movl $0x1, %edx
callq 0x2dca8
jmp 0x2b727
xorl %ebp, %ebp
movq 0x120(%rsp), %rax
decl %r15d
movq %rbp, (%rax)
movq 0x40(%rsp), %rax
leal -0x1(%rax), %ecx
movq 0x28(%rsp), %rbx
testl %ebx, %ebx
movl %ecx, 0x34(%rsp)
jle 0x2be30
movq 0x58(%rsp), %rax
addl $0x7e, %eax
movq %rax, 0xa0(%rsp)
subl %ebx, %eax
movq %rax, 0x98(%rsp)
movl $0x40, %eax
subl 0x30(%rsp), %eax
movl %eax, 0x54(%rsp)
movq 0x60(%rsp), %rax
incl %eax
movq %rax, 0x60(%rsp)
movl %r14d, %eax
movq %rax, 0xc0(%rsp)
movl %ebx, %eax
movq %rax, 0xb8(%rsp)
movslq %ecx, %rax
movq %rax, 0xa8(%rsp)
movq 0x10(%rsp), %rax
addq $0x10, %rax
movq %rax, 0x90(%rsp)
movq 0x80(%rsp), %rax
leaq (,%rax,4), %rax
movq %rax, 0xb0(%rsp)
movq $0x0, 0x70(%rsp)
movq $0x0, 0x68(%rsp)
xorl %r13d, %r13d
xorl %r12d, %r12d
movq 0x18(%rsp), %r14
movq 0x20(%rsp), %rbp
movq %r13, %rcx
movzbl (%rbp), %eax
imull 0x40(%rsp), %eax
movslq %eax, %r8
movslq %r12d, %rax
leaq (%rax,%rax,2), %rsi
movq 0x10(%rsp), %rdx
leaq (%rdx,%rsi,8), %rdx
movl $0x1, %edi
cmpl %r15d, %eax
movq %r15, 0x8(%rsp)
movq %rbp, 0x20(%rsp)
movq %rsi, 0x48(%rsp)
movq %r8, 0x38(%rsp)
jg 0x2b8f0
movq %r14, 0x18(%rsp)
leaq (,%r8,8), %rdi
leaq (%rdi,%rax,8), %r8
addq 0x88(%rsp), %r8
movl %r15d, %r9d
subl %eax, %r9d
incl %r9d
movl $0x1, %edi
xorl %r10d, %r10d
movl %edi, %r11d
movq (%rdx), %rdi
movq 0x8(%rdx), %r13
movq (%r8,%r10,8), %rbp
movl %r11d, %ebx
shrl $0x2, %ebx
andl $0x1, %ebx
movq %rbp, %r15
orq %r13, %r15
orq %rbx, %rbp
movq %rbp, %r14
andq %rdi, %r14
addq %rdi, %r14
xorq %rdi, %r14
orq %rbp, %r14
movq %r14, %rbp
orq %rdi, %rbp
notq %rbp
orq %r13, %rbp
andq %rdi, %r14
movq %rbp, %rdi
shrq $0x3f, %rdi
movq %r14, %r13
sarq $0x3f, %r13
addl %r13d, %edi
addq %rbp, %rbp
addq %r14, %r14
incl %r11d
shrl %r11d
orq %rbp, %r11
movq %r11, %r13
orq %r15, %r13
notq %r13
orq %rbx, %r14
orq %r13, %r14
movq %r14, (%rdx)
andq %r15, %r11
movq %r11, 0x8(%rdx)
addl %edi, 0x10(%rdx)
addq $0x18, %rdx
incq %r10
cmpl %r10d, %r9d
jne 0x2b857
movq 0x28(%rsp), %rbx
movq 0x18(%rsp), %r14
movq 0x8(%rsp), %r15
leal 0x1(%r15), %r8d
movq %r15, %rsi
leaq -0x18(%rdx), %r15
movl -0x8(%rdx), %r9d
movq %rcx, %r13
movl %r13d, %r11d
notl %r11d
addl %ebx, %r11d
movl %r8d, %r10d
shll $0x6, %r10d
movq 0x58(%rsp), %rcx
movq %rbx, %rbp
movl %ecx, %ebx
subl %r10d, %ebx
cmpl %ebx, %r11d
cmovgl %r11d, %ebx
cmpl 0x34(%rsp), %esi
movl $0x0, %r11d
cmovel 0x30(%rsp), %r11d
addl %ebx, %r11d
addl %r9d, %r11d
cmpl %r11d, %r14d
cmovgel %r11d, %r14d
cmpl 0x40(%rsp), %r8d
movq %r14, 0x18(%rsp)
jge 0x2b9f5
decl %r10d
movq 0xa0(%rsp), %rcx
leal (%rcx,%r13), %r11d
subl %r9d, %r11d
subl %ebp, %r11d
addl %r14d, %r11d
cmpl %r11d, %r10d
jg 0x2b9f5
movq 0x88(%rsp), %rcx
movq 0x38(%rsp), %rsi
leaq (%rcx,%rsi,8), %rsi
movq $0x0, 0x8(%rdx)
movslq %r8d, %r10
movq (%rsi,%r10,8), %rsi
movl %edi, %r10d
shrl $0x2, %r10d
andl $0x1, %r10d
movq %rsi, %r11
orq %r10, %r11
movq %r11, %rbx
negq %rbx
orq %r11, %rbx
movq %rbx, %r11
sarq $0x3f, %r11
addq %rbx, %rbx
leal 0x1(%rdi), %r14d
shrl %r14d
movq %r14, %r15
orq %rsi, %r15
notq %r15
orq %r10, %r15
orq %rbx, %r15
movq %r15, (%rdx)
andl %r14d, %esi
movq 0x18(%rsp), %r14
movq %rsi, 0x8(%rdx)
subl %edi, %r9d
leal (%r9,%r11), %esi
addl $0x40, %esi
movl %esi, 0x10(%rdx)
movq %rdx, %r15
movl %r8d, %ecx
movq %rcx, 0x8(%rsp)
movq 0x8(%rsp), %rcx
cmpl %r12d, %ecx
movq 0x28(%rsp), %r11
movq 0x20(%rsp), %rbp
jl 0x2ba64
leal 0x40(%r14), %edx
movq 0x98(%rsp), %rsi
addl %r13d, %esi
addl %r14d, %esi
leal -0x1(%r12), %edi
movl %ecx, %r8d
shll $0x6, %r8d
orl $0x3e, %r8d
movl 0x10(%r15), %r9d
cmpl %edx, %r9d
jge 0x2ba3f
movl %esi, %r10d
subl %r9d, %r10d
cmpl %r10d, %r8d
jle 0x2ba64
movq 0x8(%rsp), %rcx
leal -0x1(%rcx), %r9d
addq $-0x18, %r15
addl $-0x40, %r8d
cmpl %r12d, %ecx
movl %r9d, %ecx
movq %rcx, 0x8(%rsp)
jg 0x2ba2b
movl %edi, %ecx
movq %rcx, 0x8(%rsp)
movq 0x8(%rsp), %r9
cmpl %r9d, %r12d
jg 0x2bacd
leal 0x40(%r14), %edx
movq 0x58(%rsp), %rcx
leal (%rcx,%r13), %esi
subl %r14d, %esi
subl %r11d, %esi
movslq %r9d, %r8
leal 0x1(%r9), %edi
decq %rax
movq 0x90(%rsp), %rcx
movq 0x48(%rsp), %r9
leaq (%rcx,%r9,8), %rcx
movl %r12d, %r9d
shll $0x6, %r9d
orl $0x3f, %r9d
movl (%rcx), %r10d
cmpl %edx, %r10d
jge 0x2bab7
addl %esi, %r10d
cmpl %r10d, %r9d
jge 0x2bacd
incq %rax
addq $0x18, %rcx
incl %r12d
addl $0x40, %r9d
cmpq %r8, %rax
jl 0x2baa7
movl %edi, %r12d
testl $0x7ff, %r13d           # imm = 0x7FF
je 0x2bae0
movq 0x8(%rsp), %r15
jmp 0x2bd56
movq 0x8(%rsp), %rcx
cmpl %r12d, %ecx
movq %r13, 0x48(%rsp)
jge 0x2baf7
movq %rcx, %r15
jmp 0x2bc33
movq 0x60(%rsp), %rax
addl %r13d, %eax
addl %r14d, %eax
movl %eax, 0x7c(%rsp)
leal -0x1(%r12), %eax
movl %eax, 0x78(%rsp)
movl %ecx, %eax
shll $0x6, %eax
decl %eax
movl %eax, 0x38(%rsp)
movq (%r15), %rbx
movq 0x8(%r15), %r13
movl 0x10(%r15), %r14d
movl $0x100, %edi            # imm = 0x100
callq 0x63b0
movq %rax, %rbp
movl $0xfc, %edx
movq %rax, %rdi
xorl %esi, %esi
callq 0x6240
xorl %eax, %eax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
movl %r14d, (%rbp,%rax,4)
movq %rcx, %rdx
andq %rbx, %rdx
cmpq $0x1, %rdx
adcl $-0x1, %r14d
movq %rcx, %rdx
andq %r13, %rdx
cmpq $0x1, %rdx
sbbl $-0x1, %r14d
shrq %rcx
incq %rax
cmpq $0x3f, %rax
jne 0x2bb4d
movl %r14d, 0xfc(%rbp)
movl 0x34(%rsp), %eax
cmpl %eax, 0x8(%rsp)
movl $0x40, %eax
cmovel 0x54(%rsp), %eax
testl %eax, %eax
movq 0x18(%rsp), %r14
movl 0x7c(%rsp), %edi
jle 0x2bbd0
movslq %eax, %rdx
movl $0x41, %ecx
subq %rdx, %rcx
addl 0x38(%rsp), %eax
movl -0x4(%rbp,%rcx,4), %edx
cmpl %r14d, %edx
jg 0x2bbc0
movl %edi, %esi
subl %edx, %esi
cmpl %esi, %eax
jle 0x2bc12
movq %rcx, %rdx
incq %rdx
decl %eax
cmpl $0x40, %ecx
movq %rdx, %rcx
jne 0x2bbaf
movq 0x8(%rsp), %r13
leal -0x1(%r13), %ebx
addq $-0x18, %r15
movl $0x100, %esi            # imm = 0x100
movq %rbp, %rdi
callq 0x63c0
addl $-0x40, 0x38(%rsp)
cmpl %r12d, %r13d
movl %ebx, %eax
movq %rax, 0x8(%rsp)
jg 0x2bb1a
movl 0x78(%rsp), %eax
movl %eax, %r15d
movq 0x28(%rsp), %r11
movq 0x20(%rsp), %rbp
jmp 0x2bc2e
movl $0x100, %esi            # imm = 0x100
movq %rbp, %rdi
callq 0x63c0
movq 0x28(%rsp), %r11
movq 0x20(%rsp), %rbp
movq 0x8(%rsp), %r15
movq 0x48(%rsp), %r13
cmpl %r15d, %r12d
jg 0x2bd56
movl %r13d, %ecx
addl 0x58(%rsp), %ecx
subl %r14d, %ecx
subl %r11d, %ecx
movl %ecx, 0x38(%rsp)
movslq %r12d, %rbx
leal 0x1(%r15), %r12d
movq %r15, 0x8(%rsp)
leaq (%rbx,%rbx,2), %rax
movq 0x10(%rsp), %rcx
movq (%rcx,%rax,8), %r15
movq 0x8(%rcx,%rax,8), %r13
movl 0x10(%rcx,%rax,8), %r14d
movl $0x100, %edi            # imm = 0x100
callq 0x63b0
movq %rax, %rbp
movl $0xfc, %edx
movq %rax, %rdi
xorl %esi, %esi
callq 0x6240
xorl %eax, %eax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
movl %r14d, (%rbp,%rax,4)
movq %rcx, %rdx
andq %r15, %rdx
cmpq $0x1, %rdx
adcl $-0x1, %r14d
movq %rcx, %rdx
andq %r13, %rdx
cmpq $0x1, %rdx
sbbl $-0x1, %r14d
shrq %rcx
incq %rax
cmpq $0x3f, %rax
jne 0x2bc98
movl %r14d, 0xfc(%rbp)
cmpq 0xa8(%rsp), %rbx
movl $0x40, %ecx
cmovel 0x54(%rsp), %ecx
testl %ecx, %ecx
movq 0x18(%rsp), %r14
movq 0x8(%rsp), %r15
movq 0x48(%rsp), %r13
movl 0x38(%rsp), %esi
jle 0x2bd26
movl %ebx, %eax
shll $0x6, %eax
addl %ecx, %eax
movslq %ecx, %rdx
movl $0x41, %ecx
subq %rdx, %rcx
movl -0x4(%rbp,%rcx,4), %edx
cmpl %r14d, %edx
jg 0x2bd16
addl %esi, %edx
cmpl %edx, %eax
jg 0x2bd41
decl %eax
movq %rcx, %rdx
incq %rdx
cmpl $0x40, %ecx
movq %rdx, %rcx
jne 0x2bd07
incq %rbx
movl $0x100, %esi            # imm = 0x100
movq %rbp, %rdi
callq 0x63c0
cmpl %ebx, %r12d
jne 0x2bc59
jmp 0x2bd51
movl $0x100, %esi            # imm = 0x100
movq %rbp, %rdi
callq 0x63c0
movl %ebx, %r12d
movq 0x20(%rsp), %rbp
movl %r15d, %eax
subl %r12d, %eax
jl 0x2bede
cmpb $0x0, 0x118(%rsp)
je 0x2bde3
movslq %r12d, %r9
leaq (%r9,%r9,2), %rcx
movq 0x10(%rsp), %rdx
leaq (%rdx,%rcx,8), %rcx
movq 0x120(%rsp), %rdx
movq (%rdx), %r10
movq 0x18(%r10), %rdx
movq 0x20(%r10), %rsi
movq 0x68(%rsp), %rdi
addq %r9, %rdi
shlq $0x3, %rdi
movq (%r10), %r8
addq %rdi, %r8
addq 0x8(%r10), %rdi
movq 0x70(%rsp), %r11
leaq (%r11,%r9,4), %r9
addq 0x10(%r10), %r9
leal 0x1(%rax), %r10d
xorl %r11d, %r11d
movq (%rcx), %rbx
movq %rbx, (%r8,%r11,8)
movq 0x8(%rcx), %rbx
movq %rbx, (%rdi,%r11,8)
movl 0x10(%rcx), %ebx
movl %ebx, (%r9,%r11,4)
movl %r12d, (%rdx,%r13,4)
movl %r15d, (%rsi,%r13,4)
incq %r11
addq $0x18, %rcx
cmpl %r11d, %r10d
jne 0x2bdb9
cmpq 0xc0(%rsp), %r13
je 0x2befc
incq %rbp
incq %r13
movq 0x68(%rsp), %rax
addq 0x80(%rsp), %rax
movq %rax, 0x68(%rsp)
movq 0x70(%rsp), %rax
addq 0xb0(%rsp), %rax
movq %rax, 0x70(%rsp)
cmpq 0xb8(%rsp), %r13
movq 0x28(%rsp), %rbx
jne 0x2b7ec
jmp 0x2be35
movq 0x18(%rsp), %r14
movl 0x34(%rsp), %eax
cmpl %eax, %r15d
jne 0x2bede
movq %r14, 0x18(%rsp)
movabsq $-0x8000000000000000, %rbx # imm = 0x8000000000000000
cltq
leaq (%rax,%rax,2), %rax
movq 0x10(%rsp), %rcx
movq (%rcx,%rax,8), %r14
movq 0x8(%rcx,%rax,8), %r12
movl 0x10(%rcx,%rax,8), %ebp
movl $0x100, %edi            # imm = 0x100
callq 0x63b0
movq %rax, %r15
xorl %r13d, %r13d
movl $0xfc, %edx
movq %rax, %rdi
xorl %esi, %esi
callq 0x6240
movl %ebp, (%r15,%r13,4)
movq %rbx, %rax
andq %r14, %rax
cmpq $0x1, %rax
adcl $-0x1, %ebp
movq %rbx, %rax
andq %r12, %rax
cmpq $0x1, %rax
sbbl $-0x1, %ebp
shrq %rbx
incq %r13
cmpq $0x3f, %r13
jne 0x2be88
movl %ebp, 0xfc(%r15)
movslq 0x30(%rsp), %rax
movl (%r15,%rax,4), %ebx
movl $0x100, %esi            # imm = 0x100
movq %r15, %rdi
callq 0x63c0
cmpl 0x18(%rsp), %ebx
movq 0x28(%rsp), %rcx
jle 0x2bf8c
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movq 0x110(%rsp), %rcx
movl %eax, (%rcx)
movq 0x108(%rsp), %rcx
movl %eax, (%rcx)
jmp 0x2bfa2
movq 0x120(%rsp), %rcx
movq (%rcx), %r10
movq 0x18(%r10), %rcx
movq 0x20(%r10), %rdx
movslq %r12d, %rsi
leaq (%rsi,%rsi,2), %rdi
movq 0x10(%rsp), %r8
leaq (%r8,%rdi,8), %rdi
addq $0x10, %rdi
leaq (,%rsi,8), %r8
movq (%r10), %r9
addq %r8, %r9
addq 0x8(%r10), %r8
shlq $0x2, %rsi
addq 0x10(%r10), %rsi
incl %eax
xorl %r10d, %r10d
movq -0x10(%rdi), %r11
movq %r11, (%r9,%r10,8)
movq -0x8(%rdi), %r11
movq %r11, (%r8,%r10,8)
movl (%rdi), %r11d
movl %r11d, (%rsi,%r10,4)
movl %r12d, (%rcx)
movl %r15d, (%rdx)
addq $0x18, %rdi
incq %r10
cmpl %r10d, %eax
jne 0x2bf42
movq 0x108(%rsp), %rax
movl $0xffffffff, (%rax)     # imm = 0xFFFFFFFF
movq 0x110(%rsp), %rax
movl 0x128(%rsp), %ecx
movl %ecx, (%rax)
jmp 0x2bfa2
movq 0x108(%rsp), %rax
movl %ebx, (%rax)
decl %ecx
movq 0x110(%rsp), %rax
movl %ecx, (%rax)
movq 0x10(%rsp), %rdi
callq 0x64f0
xorl %eax, %eax
addq $0xc8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x2bfc2
movq %rax, %rbx
movl $0x28, %esi
movq %rbp, %rdi
callq 0x63c0
movq %rbx, %rdi
callq 0x6660