// File: /workspace/github_cpp_makefile_star2_O1/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 $0xa8, %rsp
movq %r9, 0x50(%rsp)
movq %r8, 0x78(%rsp)
movl %ecx, %ebp
movl %edx, %r14d
movl %esi, 0x64(%rsp)
movq %rdi, 0x98(%rsp)
movq 0x100(%rsp), %rax
movq 0xf8(%rsp), %rcx
movl 0xe0(%rsp), %ebx
movq $0x0, (%rcx)
movl $0x0, (%rax)
leal 0x1(%rbx), %eax
testb $0x3f, %al
je 0x2ae8f
leal 0x3f(%rax), %r15d
testl %eax, %eax
cmovnsl %eax, %r15d
sarl $0x6, %r15d
incl %r15d
jmp 0x2ae95
sarl $0x6, %eax
movl %eax, %r15d
cmpl %r14d, %r15d
cmovgel %r14d, %r15d
movslq %r14d, %rax
movl $0x18, %ecx
movq %rax, 0x90(%rsp)
mulq %rcx
movq $-0x1, %rdi
cmovnoq %rax, %rdi
callq 0x6030
cmpl %ebx, %ebp
cmovgel %ebx, %ebp
cmpl $0x2, 0xe8(%rsp)
cmovnel %ebx, %ebp
movq %rax, 0x40(%rsp)
movq %rax, %rdx
testl %r15d, %r15d
movq %r15, %rbx
jle 0x2af08
movl $0x40, %eax
movl %ebx, %ecx
movq 0x40(%rsp), %rdx
movl %eax, 0x10(%rdx)
movq $-0x1, (%rdx)
movq $0x0, 0x8(%rdx)
addq $0x18, %rdx
addl $0x40, %eax
decl %ecx
jne 0x2aeeb
decl %ebx
xorl %r13d, %r13d
cmpl $0x2, 0xe8(%rsp)
setne %al
xorps %xmm0, %xmm0
movaps %xmm0, 0x10(%rsp)
movq $0x0, 0x20(%rsp)
cmpl $0x0, 0x50(%rsp)
setg 0xb(%rsp)
movq %r14, 0x80(%rsp)
jle 0x2b47b
movb %al, %r13b
leal -0x1(%r14), %eax
movl %eax, 0x6c(%rsp)
movq 0x40(%rsp), %rax
addq $0x10, %rax
movq %rax, 0x88(%rsp)
movl $0xffffffff, %r12d      # imm = 0xFFFFFFFF
xorl %r15d, %r15d
movl $0x0, 0xc(%rsp)
movl %r13d, 0x68(%rsp)
movl %r12d, 0x4(%rsp)
movq 0x78(%rsp), %rax
movzbl (%rax), %eax
imulq 0x90(%rsp), %rax
movq 0x98(%rsp), %rcx
leaq (%rcx,%rax,8), %rax
movslq %r15d, %rdx
leaq (%rdx,%rdx,2), %rsi
movq 0x40(%rsp), %rcx
movq %rsi, 0xa0(%rsp)
leaq (%rcx,%rsi,8), %r13
leaq (%rax,%rdx,8), %rax
movq %rdx, 0x48(%rsp)
cmpl %ebx, %edx
jle 0x2afc3
movl 0x68(%rsp), %ecx
jmp 0x2b058
movl %ebx, %edx
subl %r15d, %edx
incl %edx
movl 0x68(%rsp), %ecx
movl %ecx, %esi
movq (%r13), %rcx
movq 0x8(%r13), %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, (%r13)
andq %r8, %rsi
movq %rsi, 0x8(%r13)
addl %ecx, 0x10(%r13)
addq $0x18, %r13
addq $0x8, %rax
movl %ecx, %esi
decl %edx
jne 0x2afd0
cmpl 0x6c(%rsp), %ebx
jge 0x2b076
movl -0x8(%r13), %edx
subl %ecx, %edx
cmpl %ebp, %edx
jg 0x2b076
movq (%rax), %rax
testl %ecx, %ecx
js 0x2b09e
movl %eax, %esi
andl $0x1, %esi
jne 0x2b09e
addq $-0x18, %r13
cmpl %r15d, %ebx
jl 0x2b0e8
leal 0x40(%rbp), %ecx
leal -0x1(%r15), %eax
cmpl %ecx, 0x10(%r13)
jl 0x2b0e8
leal -0x1(%rbx), %edx
addq $-0x18, %r13
cmpl %r15d, %ebx
movl %edx, %ebx
jg 0x2b086
movl %eax, %ebx
jmp 0x2b0e8
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, (%r13)
andl %ecx, %eax
movq %rax, 0x8(%r13)
leal (%rdx,%rdi), %eax
addl $0x40, %eax
movl %eax, 0x10(%r13)
testl $0x7ff, 0xc(%rsp)       # imm = 0x7FF
movq %rbp, 0x30(%rsp)
jne 0x2b1e0
testl %ebx, %ebx
js 0x2b1e0
movq %r15, 0x58(%rsp)
cmpl %r15d, %ebx
jl 0x2b1e0
movq %rbx, %r15
movq (%r13), %rbx
movq 0x8(%r13), %r12
movl 0x10(%r13), %ebp
movl $0x100, %edi            # imm = 0x100
callq 0x63b0
movq %rax, %r14
movl $0x100, %edx            # imm = 0x100
movq %rax, %rdi
xorl %esi, %esi
callq 0x6240
xorl %eax, %eax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
movl %ebp, (%r14,%rax,4)
movq %rcx, %rdx
andq %rbx, %rdx
cmpq $0x1, %rdx
adcl $-0x1, %ebp
movq %rcx, %rdx
andq %r12, %rdx
cmpq $0x1, %rdx
sbbl $-0x1, %ebp
shrq %rcx
incq %rax
cmpq $0x3f, %rax
jne 0x2b148
movl %ebp, 0xfc(%r14)
movq 0x30(%rsp), %rbp
cmpl %ebp, (%r14)
jle 0x2b1cb
xorl %eax, %eax
movq %rax, %rbx
cmpq $0x3f, %rax
je 0x2b199
leaq 0x1(%rbx), %rax
cmpl %ebp, 0x4(%r14,%rbx,4)
jg 0x2b185
movl $0x100, %esi            # imm = 0x100
movq %r14, %rdi
callq 0x63c0
cmpq $0x3f, %rbx
jb 0x2b1d8
leal -0x1(%r15), %eax
addq $-0x18, %r13
testl %r15d, %r15d
movl %eax, %ebx
movq 0x58(%rsp), %r15
jg 0x2b108
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
jmp 0x2b1e0
movl $0x100, %esi            # imm = 0x100
movq %r14, %rdi
callq 0x63c0
movq %r15, %rbx
movq 0x58(%rsp), %r15
movl 0xe8(%rsp), %edx
cmpl $0x2, %edx
sete %al
cmpl $-0x1, %ebx
sete %cl
leaq 0x18(%r13), %rsi
testb %cl, %al
cmoveq %r13, %rsi
movq %rsi, 0x70(%rsp)
movl $0x0, %eax
cmovnel %eax, %ebx
cmpl $0x2, %edx
jne 0x2b219
movl 0x4(%rsp), %r12d
jmp 0x2b360
cmpl %ebx, %r15d
movl 0x4(%rsp), %r12d
jg 0x2b25e
leal 0x40(%rbp), %eax
movslq %ebx, %rcx
leal 0x1(%rbx), %edx
movq 0x48(%rsp), %rdi
decq %rdi
movq 0x88(%rsp), %rsi
movq 0xa0(%rsp), %r8
leaq (%rsi,%r8,8), %rsi
cmpl %eax, (%rsi)
jl 0x2b25e
incl %r15d
incq %rdi
addq $0x18, %rsi
cmpq %rcx, %rdi
jl 0x2b248
movl %edx, %r15d
testl $0x7ff, 0xc(%rsp)       # imm = 0x7FF
jne 0x2b360
cmpl %ebx, %r15d
jg 0x2b360
movslq %r15d, %r13
movslq %ebx, %rax
movq %rax, 0x58(%rsp)
movq %rbx, 0x48(%rsp)
leal 0x1(%rbx), %r15d
leaq (,%r13,2), %rax
addq %r13, %rax
movq 0x40(%rsp), %rcx
movq (%rcx,%rax,8), %rbx
movq 0x8(%rcx,%rax,8), %r12
movl 0x10(%rcx,%rax,8), %ebp
movl $0x100, %edi            # imm = 0x100
callq 0x63b0
movq %rax, %r14
movl $0x100, %edx            # imm = 0x100
movq %rax, %rdi
xorl %esi, %esi
callq 0x6240
xorl %eax, %eax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
movl %ebp, (%r14,%rax,4)
movq %rcx, %rdx
andq %rbx, %rdx
cmpq $0x1, %rdx
adcl $-0x1, %ebp
movq %rcx, %rdx
andq %r12, %rdx
cmpq $0x1, %rdx
sbbl $-0x1, %ebp
shrq %rcx
incq %rax
cmpq $0x3f, %rax
jne 0x2b2ce
movl %ebp, 0xfc(%r14)
movq 0x30(%rsp), %rbp
cmpl %ebp, (%r14)
jle 0x2b346
xorl %eax, %eax
movq %rax, %rbx
cmpq $0x3f, %rax
je 0x2b31f
leaq 0x1(%rbx), %rax
cmpl %ebp, 0x4(%r14,%rbx,4)
jg 0x2b30b
movl $0x100, %esi            # imm = 0x100
movq %r14, %rdi
callq 0x63c0
cmpq $0x3f, %rbx
jb 0x2b353
leaq 0x1(%r13), %rax
cmpq 0x58(%rsp), %r13
movq %rax, %r13
jl 0x2b289
jmp 0x2b356
movl $0x100, %esi            # imm = 0x100
movq %r14, %rdi
callq 0x63c0
movl %r13d, %r15d
movl 0x4(%rsp), %r12d
movq 0x48(%rsp), %rbx
cmpl %r15d, %ebx
jge 0x2b3e4
movq 0xf0(%rsp), %rax
movl %r12d, (%rax)
cmpl $-0x1, %r12d
je 0x2b3d3
movq 0x10(%rsp), %r14
movq 0x18(%rsp), %rbp
movq %rbp, %rdi
subq %r14, %rdi
movq %r15, %r13
movq %rbx, %r15
movq %rdi, %rbx
shrq $0x2, %rbx
shlq $0x1e, %rdi
sarq $0x1e, %rdi
callq 0x6530
movq 0xf8(%rsp), %rcx
movq %rax, (%rcx)
movq 0x100(%rsp), %rcx
movl %ebx, (%rcx)
movq %r15, %rbx
movq %r13, %r15
movl 0x4(%rsp), %r12d
subq %r14, %rbp
je 0x2b3d3
movq %rax, %rdi
movq %r14, %rsi
movq %rbp, %rdx
callq 0x65f0
movq 0x40(%rsp), %rdi
callq 0x64f0
movq 0x30(%rsp), %rbp
jmp 0x2b45b
cmpl 0x6c(%rsp), %ebx
jne 0x2b456
movq 0x70(%rsp), %rax
movl 0x10(%rax), %eax
cmpl %ebp, %eax
jg 0x2b456
cmpl $-0x1, %r12d
setne %cl
cmpl %r12d, %eax
setg %dl
testb %dl, %cl
jne 0x2b456
cmpl %r12d, %eax
je 0x2b422
movq 0x10(%rsp), %rcx
cmpq %rcx, 0x18(%rsp)
je 0x2b41d
movq %rcx, 0x18(%rsp)
movl %eax, %r12d
movl %eax, %ebp
movl 0xc(%rsp), %eax
subl 0x64(%rsp), %eax
movl %eax, 0x3c(%rsp)
movq 0x18(%rsp), %rsi
cmpq 0x20(%rsp), %rsi
je 0x2b447
movl %eax, (%rsi)
addq $0x4, %rsi
movq %rsi, 0x18(%rsp)
jmp 0x2b456
leaq 0x10(%rsp), %rdi
leaq 0x3c(%rsp), %rdx
callq 0x2d782
incq 0x78(%rsp)
cmpl %r15d, %ebx
jl 0x2b486
movl 0xc(%rsp), %eax
incl %eax
movl %eax, 0xc(%rsp)
cmpl 0x50(%rsp), %eax
setl 0xb(%rsp)
jne 0x2af73
jmp 0x2b486
movq %rdx, 0x70(%rsp)
movl $0xffffffff, %r12d      # imm = 0xFFFFFFFF
testb $0x1, 0xb(%rsp)
jne 0x2b626
movq 0x80(%rsp), %rax
decl %eax
cmpl %eax, %ebx
jne 0x2b5bf
movq %rbp, 0x30(%rsp)
movl %r12d, 0x4(%rsp)
movq 0x70(%rsp), %rax
movq (%rax), %rbx
movq 0x8(%rax), %r14
movl 0x10(%rax), %ebp
movl $0x100, %edi            # imm = 0x100
callq 0x63b0
movq %rax, %r15
movabsq $-0x8000000000000000, %r13 # imm = 0x8000000000000000
xorl %r12d, %r12d
movl $0x100, %edx            # imm = 0x100
movq %rax, %rdi
xorl %esi, %esi
callq 0x6240
movl %ebp, (%r15,%r12,4)
movq %r13, %rax
andq %rbx, %rax
cmpq $0x1, %rax
adcl $-0x1, %ebp
movq %r13, %rax
andq %r14, %rax
cmpq $0x1, %rax
sbbl $-0x1, %ebp
shrq %r13
incq %r12
cmpq $0x3f, %r12
jne 0x2b4e5
movl %ebp, 0xfc(%r15)
movl 0x64(%rsp), %eax
testl %eax, %eax
jle 0x2b5ad
movl %eax, %ebx
movl %eax, %ecx
movq 0x50(%rsp), %rax
subl %ecx, %eax
movq %rax, 0x50(%rsp)
xorl %r14d, %r14d
leaq 0x10(%rsp), %r13
leaq 0x3c(%rsp), %rbp
movl 0x4(%r15,%r14,4), %eax
cmpl 0x30(%rsp), %eax
jg 0x2b5a5
movl 0x4(%rsp), %ecx
cmpl $-0x1, %ecx
je 0x2b557
cmpl %ecx, %eax
jg 0x2b5a5
cmpl %ecx, %eax
je 0x2b575
movq 0x10(%rsp), %rcx
cmpq %rcx, 0x18(%rsp)
je 0x2b56c
movq %rcx, 0x18(%rsp)
movl %eax, 0x4(%rsp)
movq %rax, 0x30(%rsp)
movq 0x50(%rsp), %rax
addq %r14, %rax
movl %eax, 0x3c(%rsp)
movq 0x18(%rsp), %rsi
cmpq 0x20(%rsp), %rsi
je 0x2b59a
movl %eax, (%rsi)
addq $0x4, %rsi
movq %rsi, 0x18(%rsp)
jmp 0x2b5a5
movq %r13, %rdi
movq %rbp, %rdx
callq 0x2d782
incq %r14
cmpq %r14, %rbx
jne 0x2b53f
movl $0x100, %esi            # imm = 0x100
movq %r15, %rdi
callq 0x63c0
movl 0x4(%rsp), %r12d
movq 0xf0(%rsp), %rax
movl %r12d, (%rax)
cmpl $-0x1, %r12d
je 0x2b61c
movq 0x10(%rsp), %r14
movq 0x18(%rsp), %r15
movq %r15, %rdi
subq %r14, %rdi
movq %rdi, %rbx
shrq $0x2, %rbx
shlq $0x1e, %rdi
sarq $0x1e, %rdi
callq 0x6530
movq 0xf8(%rsp), %rcx
movq %rax, (%rcx)
movq 0x100(%rsp), %rcx
movl %ebx, (%rcx)
subq %r14, %r15
je 0x2b61c
movq %rax, %rdi
movq %r14, %rsi
movq %r15, %rdx
callq 0x65f0
movq 0x40(%rsp), %rdi
callq 0x64f0
movq 0x10(%rsp), %rdi
testq %rdi, %rdi
je 0x2b63d
movq 0x20(%rsp), %rsi
subq %rdi, %rsi
callq 0x63c0
addq $0xa8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x2b667
jmp 0x2b667
movq %rax, %rbx
movl $0x100, %esi            # imm = 0x100
movq %r15, %rdi
callq 0x63c0
jmp 0x2b66a
jmp 0x2b667
movq %rax, %rbx
movq 0x10(%rsp), %rdi
testq %rdi, %rdi
je 0x2b681
movq 0x20(%rsp), %rsi
subq %rdi, %rsi
callq 0x63c0
movq %rbx, %rdi
callq 0x6660