// File: /workspace/github_cpp_makefile_star2_O3/VanAndelInstitute[P]intent/src/edlib.cpp
// Function: myersCalcEditDistanceSemiGlobal(unsigned long const*, int, int, int, unsigned char const*, int, int, EdlibAlignMode, int*, int**, int*)
static int myersCalcEditDistanceSemiGlobal(
        const Word* const Peq, const int W, const int maxNumBlocks,
        const int queryLength,
        const unsigned char* const target, const int targetLength,
        int k, const EdlibAlignMode mode,
        int* const bestScore_, int** const positions_, int* const numPositions_) {
    *positions_ = NULL;
    *numPositions_ = 0;

    // 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;
    int lastBlock = min(ceilDiv(k + 1, WORD_SIZE), maxNumBlocks) - 1; // y in Myers
    Block *bl; // Current block

    Block* blocks = new Block[maxNumBlocks];

    // For HW, solution will never be larger then queryLength.
    if (mode == EDLIB_MODE_HW) {
        k = min(queryLength, k);
    }

    // Each STRONG_REDUCE_NUM column is reduced in more expensive way.
    // This gives speed up of about 2 times for small k.
    const int STRONG_REDUCE_NUM = 2048;

    // 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++;
    }

    int bestScore = -1;
    vector<int> positions; // TODO: Maybe put this on heap?
    const int startHout = mode == EDLIB_MODE_HW ? 0 : 1; // If 0 then gap before query is not penalized;
    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 = startHout;
        bl = blocks + firstBlock;
        Peq_c += firstBlock;
        for (int b = firstBlock; b <= lastBlock; b++) {
            hout = calculateBlock(bl->P, bl->M, *Peq_c, hout, bl->P, bl->M);
            bl->score += hout;
            bl++; Peq_c++;
        }
        bl--; Peq_c--;
        //------------------------------------------------------------------//

        //---------- Adjust number of blocks according to Ukkonen ----------//
        if ((lastBlock < maxNumBlocks - 1) && (bl->score - hout <= k) // bl is pointing to last block
            && ((*(Peq_c + 1) & WORD_1) || hout < 0)) { // Peq_c is pointing to last block
            // If score of left block is not too big, calculate one more block
            lastBlock++; bl++; Peq_c++;
            bl->P = static_cast<Word>(-1); // All 1s
            bl->M = static_cast<Word>(0);
            bl->score = (bl - 1)->score - hout + WORD_SIZE + calculateBlock(bl->P, bl->M, *Peq_c, hout, bl->P, bl->M);
        } else {
            while (lastBlock >= firstBlock && bl->score >= k + WORD_SIZE) {
                lastBlock--; bl--; Peq_c--;
            }
        }

        // Every some columns, do some expensive but also more efficient block reducing.
        // This is important!
        //
        // Reduce the band by decreasing last block if possible.
        if (c % STRONG_REDUCE_NUM == 0) {
            while (lastBlock >= 0 && lastBlock >= firstBlock && allBlockCellsLarger(*bl, k)) {
                lastBlock--; bl--; Peq_c--;
            }
        }
        // For HW, even if all cells are > k, there still may be solution in next
        // column because starting conditions at upper boundary are 0.
        // That means that first block is always candidate for solution,
        // and we can never end calculation before last column.
        if (mode == EDLIB_MODE_HW && lastBlock == -1) {
            lastBlock++; bl++; Peq_c++;
        }

        // Reduce band by increasing first block if possible. Not applicable to HW.
        if (mode != EDLIB_MODE_HW) {
            while (firstBlock <= lastBlock && blocks[firstBlock].score >= k + WORD_SIZE) {
                firstBlock++;
            }
            if (c % STRONG_REDUCE_NUM == 0) { // Do strong reduction every some blocks
                while (firstBlock <= lastBlock && allBlockCellsLarger(blocks[firstBlock], k)) {
                    firstBlock++;
                }
            }
        }

        // If band stops to exist finish
        if (lastBlock < firstBlock) {
            *bestScore_ = bestScore;
            if (bestScore != -1) {
                *positions_ = static_cast<int *>(malloc(sizeof(int) * static_cast<int>(positions.size())));
                *numPositions_ = static_cast<int>(positions.size());
                copy(positions.begin(), positions.end(), *positions_);
            }
            delete[] blocks;
            return EDLIB_STATUS_OK;
        }
        //------------------------------------------------------------------//

        //------------------------- Update best score ----------------------//
        if (lastBlock == maxNumBlocks - 1) {
            int colScore = bl->score;
            if (colScore <= k) { // Scores > k dont have correct values (so we cannot use them), but are certainly > k.
                // NOTE: Score that I find in column c is actually score from column c-W
                if (bestScore == -1 || colScore <= bestScore) {
                    if (colScore != bestScore) {
                        positions.clear();
                        bestScore = colScore;
                        // Change k so we will look only for equal or better
                        // scores then the best found so far.
                        k = bestScore;
                    }
                    positions.push_back(c - W);
                }
            }
        }
        //------------------------------------------------------------------//

        targetChar++;
    }


    // Obtain results for last W columns from last column.
    if (lastBlock == maxNumBlocks - 1) {
        vector<int> blockScores = getBlockCellValues(*bl);
        for (int i = 0; i < W; i++) {
            int colScore = blockScores[i + 1];
            if (colScore <= k && (bestScore == -1 || colScore <= bestScore)) {
                if (colScore != bestScore) {
                    positions.clear();
                    k = bestScore = colScore;
                }
                positions.push_back(targetLength - W + i);
            }
        }
    }

    *bestScore_ = bestScore;
    if (bestScore != -1) {
        *positions_ = static_cast<int *>(malloc(sizeof(int) * static_cast<int>(positions.size())));
        *numPositions_ = static_cast<int>(positions.size());
        copy(positions.begin(), positions.end(), *positions_);
    }

    delete[] blocks;
    return EDLIB_STATUS_OK;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x88, %rsp
movq %r9, 0x50(%rsp)
movq %r8, %r14
movl %ecx, %ebp
movl %edx, 0x8(%rsp)
movq %rdi, 0x80(%rsp)
movq 0xe0(%rsp), %rax
movq 0xd8(%rsp), %rcx
movl 0xc0(%rsp), %ebx
movq $0x0, (%rcx)
movl $0x0, (%rax)
leal 0x1(%rbx), %eax
testb $0x3f, %al
movl %esi, 0x68(%rsp)
je 0x2adec
leal 0x3f(%rax), %r15d
testl %eax, %eax
cmovnsl %eax, %r15d
sarl $0x6, %r15d
incl %r15d
jmp 0x2adf2
sarl $0x6, %eax
movl %eax, %r15d
movl 0x8(%rsp), %eax
cmpl %eax, %r15d
cmovgel %eax, %r15d
cltq
movl $0x18, %ecx
movq %rax, 0x78(%rsp)
mulq %rcx
movq $-0x1, %rdi
cmovnoq %rax, %rdi
callq 0x6030
cmpl %ebx, %ebp
cmovgel %ebx, %ebp
cmpl $0x2, 0xc8(%rsp)
cmovnel %ebx, %ebp
movq %rax, 0x60(%rsp)
movq %rax, %r12
testl %r15d, %r15d
movq %r15, %r13
jle 0x2ae6a
movl $0x40, %eax
movl %r13d, %ecx
movq 0x60(%rsp), %r12
movl %eax, 0x10(%r12)
movq $-0x1, (%r12)
movq $0x0, 0x8(%r12)
addq $0x18, %r12
addl $0x40, %eax
decl %ecx
jne 0x2ae49
decl %r13d
xorl %ecx, %ecx
cmpl $0x2, 0xc8(%rsp)
setne %al
xorps %xmm0, %xmm0
movaps %xmm0, 0x20(%rsp)
movq $0x0, 0x30(%rsp)
decl 0x8(%rsp)
cmpl $0x0, 0x50(%rsp)
jle 0x2b385
movb %al, %cl
movl %ecx, 0x6c(%rsp)
movq 0x60(%rsp), %rax
addq $0x10, %rax
movq %rax, 0x70(%rsp)
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
xorl %r15d, %r15d
movl $0x0, 0xc(%rsp)
movl %ecx, 0x4(%rsp)
movq %r14, 0x58(%rsp)
movzbl (%r14), %eax
imulq 0x78(%rsp), %rax
movq 0x80(%rsp), %rcx
leaq (%rcx,%rax,8), %rax
movslq %r15d, %rdx
leaq (%rdx,%rdx,2), %rsi
movq 0x60(%rsp), %rcx
movq %rsi, 0x40(%rsp)
leaq (%rcx,%rsi,8), %r12
leaq (%rax,%rdx,8), %rax
movq %r13, %rbx
movq %rdx, 0x48(%rsp)
cmpl %ebx, %edx
jle 0x2af0b
movl 0x6c(%rsp), %ecx
jmp 0x2afa3
movl %ebx, %edx
subl %r15d, %edx
incl %edx
movl 0x6c(%rsp), %ecx
movl %ecx, %esi
movq (%r12), %rcx
movq 0x8(%r12), %r10
movq (%rax), %r11
movl %esi, %edi
shrl $0x2, %edi
andl $0x1, %edi
movq %r11, %r8
orq %r10, %r8
orq %rdi, %r11
movq %r11, %r9
andq %rcx, %r9
addq %rcx, %r9
xorq %rcx, %r9
orq %r11, %r9
movq %r9, %r11
orq %rcx, %r11
notq %r11
orq %r10, %r11
andq %rcx, %r9
movq %r11, %rcx
shrq $0x3f, %rcx
movq %r9, %r10
sarq $0x3f, %r10
addl %r10d, %ecx
addq %r11, %r11
addq %r9, %r9
incl %esi
shrl %esi
orq %r11, %rsi
movq %rsi, %r10
orq %r8, %r10
notq %r10
orq %rdi, %r9
orq %r10, %r9
movq %r9, (%r12)
andq %r8, %rsi
movq %rsi, 0x8(%r12)
addl %ecx, 0x10(%r12)
addq $0x18, %r12
addq $0x8, %rax
movl %ecx, %esi
decl %edx
jne 0x2af18
cmpl 0x8(%rsp), %ebx
jge 0x2afc2
movl -0x8(%r12), %edx
subl %ecx, %edx
cmpl %ebp, %edx
jg 0x2afc2
movq (%rax), %rax
testl %ecx, %ecx
js 0x2afeb
movl %eax, %esi
andl $0x1, %esi
jne 0x2afeb
addq $-0x18, %r12
cmpl %ebx, %r15d
jg 0x2b037
leal 0x40(%rbp), %ecx
leal -0x1(%r15), %eax
cmpl %ecx, 0x10(%r12)
jl 0x2b037
leal -0x1(%rbx), %edx
addq $-0x18, %r12
cmpl %r15d, %ebx
movl %edx, %ebx
jg 0x2afd2
movl %eax, %ebx
jmp 0x2b037
incl %ebx
movl %ecx, %esi
shrl $0x2, %esi
andl $0x1, %esi
movq %rax, %rdi
orq %rsi, %rdi
movq %rdi, %r8
negq %r8
orq %rdi, %r8
movq %r8, %rdi
sarq $0x3f, %rdi
addq %r8, %r8
incl %ecx
shrl %ecx
movq %rcx, %r9
orq %rax, %r9
notq %r9
orq %rsi, %r9
orq %r8, %r9
movq %r9, (%r12)
andl %ecx, %eax
movq %rax, 0x8(%r12)
leal (%rdx,%rdi), %eax
addl $0x40, %eax
movl %eax, 0x10(%r12)
testl $0x7ff, 0xc(%rsp)       # imm = 0x7FF
movq %rbp, 0x38(%rsp)
jne 0x2b145
testl %ebx, %ebx
js 0x2b145
movq %r15, 0x10(%rsp)
cmpl %r15d, %ebx
jl 0x2b145
movq %rbx, %r15
movq (%r12), %r13
movq 0x8(%r12), %rbp
movl 0x10(%r12), %ebx
movl $0x100, %edi            # imm = 0x100
callq 0x63b0
movq %rax, %r14
movl $0xfc, %edx
movq %rax, %rdi
xorl %esi, %esi
callq 0x6240
xorl %eax, %eax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
movl %ebx, (%r14,%rax,4)
movq %rcx, %rdx
andq %r13, %rdx
cmpq $0x1, %rdx
adcl $-0x1, %ebx
movq %rcx, %rdx
andq %rbp, %rdx
cmpq $0x1, %rdx
sbbl $-0x1, %ebx
shrq %rcx
incq %rax
cmpq $0x3f, %rax
jne 0x2b099
movl %ebx, 0xfc(%r14)
movq 0x38(%rsp), %rbp
cmpl %ebp, (%r14)
jle 0x2b130
movq $-0x1, %rax
cmpq $0x3e, %rax
je 0x2b104
leaq 0x1(%rax), %rbx
cmpl %ebp, 0x8(%r14,%rax,4)
movq %rbx, %rax
jg 0x2b0db
movl $0x100, %esi            # imm = 0x100
movq %r14, %rdi
callq 0x63c0
cmpq $0x3f, %rbx
jae 0x2b111
jmp 0x2b13d
movl $0x100, %esi            # imm = 0x100
movq %r14, %rdi
callq 0x63c0
leal -0x1(%r15), %eax
addq $-0x18, %r12
testl %r15d, %r15d
movl %eax, %ebx
movq 0x10(%rsp), %r15
jg 0x2b057
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
jmp 0x2b145
movl $0x100, %esi            # imm = 0x100
movq %r14, %rdi
callq 0x63c0
movq %r15, %rbx
movq 0x10(%rsp), %r15
movl 0xc8(%rsp), %edx
cmpl $0x2, %edx
sete %al
cmpl $-0x1, %ebx
sete %cl
leaq 0x18(%r12), %rsi
testb %cl, %al
cmoveq %r12, %rsi
movq %rsi, %r12
movl $0x0, %eax
cmovnel %eax, %ebx
cmpl $0x2, %edx
jne 0x2b181
movq 0x58(%rsp), %r14
movl 0x4(%rsp), %edx
jmp 0x2b2e7
cmpl %ebx, %r15d
movq 0x58(%rsp), %r14
jg 0x2b1c0
leal 0x40(%rbp), %eax
movslq %ebx, %rcx
leal 0x1(%rbx), %edx
movq 0x48(%rsp), %rdi
decq %rdi
movq 0x70(%rsp), %rsi
movq 0x40(%rsp), %r8
leaq (%rsi,%r8,8), %rsi
cmpl %eax, (%rsi)
jl 0x2b1c0
incl %r15d
incq %rdi
addq $0x18, %rsi
cmpq %rcx, %rdi
jl 0x2b1aa
movl %edx, %r15d
movl 0x4(%rsp), %edx
testl $0x7ff, 0xc(%rsp)       # imm = 0x7FF
jne 0x2b2e7
cmpl %ebx, %r15d
jg 0x2b2e7
movq %r12, 0x40(%rsp)
movq %rbx, %rax
movslq %r15d, %rbx
movslq %eax, %rcx
movq %rcx, 0x10(%rsp)
movq %rax, 0x48(%rsp)
leal 0x1(%rax), %r15d
leaq (%rbx,%rbx,2), %rax
movq 0x60(%rsp), %rcx
movq (%rcx,%rax,8), %r13
movq 0x8(%rcx,%rax,8), %rbp
movl 0x10(%rcx,%rax,8), %r12d
movl $0x100, %edi            # imm = 0x100
callq 0x63b0
movq %rax, %r14
movl $0xfc, %edx
movq %rax, %rdi
xorl %esi, %esi
callq 0x6240
xorl %eax, %eax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
movl %r12d, (%r14,%rax,4)
movq %rcx, %rdx
andq %r13, %rdx
cmpq $0x1, %rdx
adcl $-0x1, %r12d
movq %rcx, %rdx
andq %rbp, %rdx
cmpq $0x1, %rdx
sbbl $-0x1, %r12d
shrq %rcx
incq %rax
cmpq $0x3f, %rax
jne 0x2b236
movl %r12d, 0xfc(%r14)
movq 0x38(%rsp), %rbp
cmpl %ebp, (%r14)
jle 0x2b2c4
movq $-0x1, %rax
cmpq $0x3e, %rax
je 0x2b2a3
leaq 0x1(%rax), %r12
cmpl %ebp, 0x8(%r14,%rax,4)
movq %r12, %rax
jg 0x2b27a
movl $0x100, %esi            # imm = 0x100
movq %r14, %rdi
callq 0x63c0
cmpq $0x3f, %r12
jae 0x2b2b0
jmp 0x2b2d1
movl $0x100, %esi            # imm = 0x100
movq %r14, %rdi
callq 0x63c0
leaq 0x1(%rbx), %rax
cmpq 0x10(%rsp), %rbx
movq %rax, %rbx
jl 0x2b1f7
jmp 0x2b2d4
movl $0x100, %esi            # imm = 0x100
movq %r14, %rdi
callq 0x63c0
movl %ebx, %r15d
movq 0x58(%rsp), %r14
movq 0x48(%rsp), %rbx
movl 0x4(%rsp), %edx
movq 0x40(%rsp), %r12
cmpl %r15d, %ebx
jl 0x2b4ae
movq %rbx, %r13
cmpl 0x8(%rsp), %ebx
jne 0x2b311
movl 0x10(%r12), %ebx
cmpl %ebp, %ebx
jg 0x2b311
cmpl $-0x1, %edx
setne %al
cmpl %edx, %ebx
setg %cl
testb %cl, %al
je 0x2b32e
movl %edx, %ebx
incq %r14
movl 0xc(%rsp), %eax
incl %eax
movl %ebx, %ecx
movl %eax, 0xc(%rsp)
cmpl 0x50(%rsp), %eax
jne 0x2aebe
jmp 0x2b38a
movq 0x28(%rsp), %rax
cmpl %edx, %ebx
jne 0x2b33e
movq %rax, %rsi
movl %edx, %ebx
jmp 0x2b354
movq 0x20(%rsp), %rsi
cmpq %rsi, %rax
je 0x2b34f
movq %rsi, 0x28(%rsp)
jmp 0x2b352
movq %rax, %rsi
movl %ebx, %ebp
movl 0xc(%rsp), %eax
subl 0x68(%rsp), %eax
movl %eax, 0x1c(%rsp)
cmpq 0x30(%rsp), %rsi
je 0x2b374
movl %eax, (%rsi)
addq $0x4, %rsi
movq %rsi, 0x28(%rsp)
jmp 0x2b313
leaq 0x20(%rsp), %rdi
leaq 0x1c(%rsp), %rdx
callq 0x2db6c
jmp 0x2b313
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
cmpl 0x8(%rsp), %r13d
jne 0x2b4d0
movq %rbp, 0x38(%rsp)
movq (%r12), %rax
movq %rax, 0x10(%rsp)
movq 0x8(%r12), %r13
movl 0x10(%r12), %ebp
movl $0x100, %edi            # imm = 0x100
callq 0x63b0
movq %rax, %r15
movabsq $-0x8000000000000000, %r12 # imm = 0x8000000000000000
xorl %r14d, %r14d
movl $0xfc, %edx
movq %rax, %rdi
xorl %esi, %esi
callq 0x6240
movq 0x10(%rsp), %rcx
movl %ebp, (%r15,%r14,4)
movq %r12, %rax
andq %rcx, %rax
cmpq $0x1, %rax
adcl $-0x1, %ebp
movq %r12, %rax
andq %r13, %rax
cmpq $0x1, %rax
sbbl $-0x1, %ebp
shrq %r12
incq %r14
cmpq $0x3f, %r14
jne 0x2b3db
movl %ebp, 0xfc(%r15)
movl 0x68(%rsp), %ecx
testl %ecx, %ecx
movq %r15, %r12
jle 0x2b4bf
movl %ecx, %r14d
movq 0x50(%rsp), %rax
subl %ecx, %eax
movq %rax, 0x50(%rsp)
xorl %r13d, %r13d
leaq 0x20(%rsp), %r15
movl 0x4(%r12,%r13,4), %ebp
cmpl 0x38(%rsp), %ebp
jg 0x2b446
cmpl $-0x1, %ebx
je 0x2b454
cmpl %ebx, %ebp
jle 0x2b454
movl %ebx, %ebp
incq %r13
movl %ebp, %ebx
cmpq %r13, %r14
jne 0x2b432
jmp 0x2b4c1
movq 0x28(%rsp), %rax
cmpl %ebx, %ebp
jne 0x2b464
movq %rax, %rsi
movl %ebx, %ebp
jmp 0x2b47f
movq 0x20(%rsp), %rsi
cmpq %rsi, %rax
je 0x2b475
movq %rsi, 0x28(%rsp)
jmp 0x2b478
movq %rax, %rsi
movl %ebp, %eax
movq %rax, 0x38(%rsp)
movq 0x50(%rsp), %rax
addq %r13, %rax
movl %eax, 0x1c(%rsp)
cmpq 0x30(%rsp), %rsi
je 0x2b49f
movl %eax, (%rsi)
addq $0x4, %rsi
movq %rsi, 0x28(%rsp)
jmp 0x2b448
movq %r15, %rdi
leaq 0x1c(%rsp), %rdx
callq 0x2db6c
jmp 0x2b448
movq 0xd0(%rsp), %rax
movl %edx, (%rax)
cmpl $-0x1, %edx
jne 0x2b4df
jmp 0x2b52b
movl %ebx, %ebp
movl $0x100, %esi            # imm = 0x100
movq %r12, %rdi
callq 0x63c0
movl %ebp, %ebx
movq 0xd0(%rsp), %rax
movl %ebx, (%rax)
cmpl $-0x1, %ebx
je 0x2b52b
movq 0x20(%rsp), %r14
movq 0x28(%rsp), %r15
movq %r15, %rdi
subq %r14, %rdi
movq %rdi, %rbx
shrq $0x2, %rbx
shlq $0x1e, %rdi
sarq $0x1e, %rdi
callq 0x6530
movq 0xd8(%rsp), %rcx
movq %rax, (%rcx)
movq 0xe0(%rsp), %rcx
movl %ebx, (%rcx)
subq %r14, %r15
je 0x2b52b
movq %rax, %rdi
movq %r14, %rsi
movq %r15, %rdx
callq 0x65f0
movq 0x60(%rsp), %rdi
callq 0x64f0
movq 0x20(%rsp), %rdi
testq %rdi, %rdi
je 0x2b54c
movq 0x30(%rsp), %rsi
subq %rdi, %rsi
callq 0x63c0
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x2b576
jmp 0x2b576
movq %rax, %rbx
movl $0x100, %esi            # imm = 0x100
movq %r12, %rdi
callq 0x63c0
jmp 0x2b579
jmp 0x2b576
movq %rax, %rbx
movq 0x20(%rsp), %rdi
testq %rdi, %rdi
je 0x2b590
movq 0x30(%rsp), %rsi
subq %rdi, %rsi
callq 0x63c0
movq %rbx, %rdi
callq 0x6660