// File: /workspace/github_c_makefile_star2_O3/nh13[P]ksw/src/parasail/src/nw_scan_sse41_128_64.c
// Function: parasail_nw_rowcol_scan_profile_sse41_128_64
parasail_result_t* PNAME(
        const parasail_profile_t * const restrict profile,
        const char * const restrict s2, const int s2Len,
        const int open, const int gap)
{
    /* declare local variables */
    int32_t i = 0;
    int32_t j = 0;
    int32_t k = 0;
    int32_t s1Len = 0;
    int32_t end_query = 0;
    int32_t end_ref = 0;
    const parasail_matrix_t *matrix = NULL;
    int32_t segWidth = 0;
    int32_t segLen = 0;
    int32_t offset = 0;
    int32_t position = 0;
    __m128i* restrict pvP = NULL;
    __m128i* restrict pvE = NULL;
    int64_t* restrict boundary = NULL;
    __m128i* restrict pvHt = NULL;
    __m128i* restrict pvH = NULL;
    __m128i* restrict pvGapper = NULL;
    __m128i vGapO;
    __m128i vGapE;
    int64_t NEG_LIMIT = 0;
    int64_t POS_LIMIT = 0;
    __m128i vZero;
    int64_t score = 0;
    __m128i vNegLimit;
    __m128i vPosLimit;
    __m128i vSaturationCheckMin;
    __m128i vSaturationCheckMax;
    __m128i vNegInfFront;
    __m128i vSegLenXgap;
    parasail_result_t *result = NULL;

    /* validate inputs */
    PARASAIL_CHECK_NULL(profile);
    PARASAIL_CHECK_NULL(profile->profile64.score);
    PARASAIL_CHECK_NULL(profile->matrix);
    PARASAIL_CHECK_GT0(profile->s1Len);
    PARASAIL_CHECK_NULL(s2);
    PARASAIL_CHECK_GT0(s2Len);
    PARASAIL_CHECK_GE0(open);
    PARASAIL_CHECK_GE0(gap);

    /* initialize stack variables */
    i = 0;
    j = 0;
    k = 0;
    s1Len = profile->s1Len;
    end_query = s1Len-1;
    end_ref = s2Len-1;
    matrix = profile->matrix;
    segWidth = 2; /* number of values in vector unit */
    segLen = (s1Len + segWidth - 1) / segWidth;
    offset = (s1Len - 1) % segLen;
    position = (segWidth - 1) - (s1Len - 1) / segLen;
    pvP = (__m128i*)profile->profile64.score;
    vGapO = _mm_set1_epi64x_rpl(open);
    vGapE = _mm_set1_epi64x_rpl(gap);
    NEG_LIMIT = (-open < matrix->min ? INT64_MIN + open : INT64_MIN - matrix->min) + 1;
    POS_LIMIT = INT64_MAX - matrix->max - 1;
    vZero = _mm_setzero_si128();
    score = NEG_LIMIT;
    vNegLimit = _mm_set1_epi64x_rpl(NEG_LIMIT);
    vPosLimit = _mm_set1_epi64x_rpl(POS_LIMIT);
    vSaturationCheckMin = vPosLimit;
    vSaturationCheckMax = vNegLimit;
    vNegInfFront = vZero;
    vNegInfFront = _mm_insert_epi64_rpl(vNegInfFront, NEG_LIMIT, 0);
    vSegLenXgap = _mm_add_epi64(vNegInfFront,
            _mm_slli_si128(_mm_set1_epi64x_rpl(-segLen*gap), 8));

    /* initialize result */
#ifdef PARASAIL_TABLE
    result = parasail_result_new_table1(segLen*segWidth, s2Len);
#else
#ifdef PARASAIL_ROWCOL
    result = parasail_result_new_rowcol1(segLen*segWidth, s2Len);
#else
    result = parasail_result_new();
#endif
#endif
    if (!result) return NULL;

    /* set known flags */
    result->flag |= PARASAIL_FLAG_NW | PARASAIL_FLAG_SCAN
        | PARASAIL_FLAG_BITS_64 | PARASAIL_FLAG_LANES_2;
#ifdef PARASAIL_TABLE
    result->flag |= PARASAIL_FLAG_TABLE;
#endif
#ifdef PARASAIL_ROWCOL
    result->flag |= PARASAIL_FLAG_ROWCOL;
#endif

    /* initialize heap variables */
    pvE = parasail_memalign___m128i(16, segLen);
    boundary = parasail_memalign_int64_t(16, s2Len+1);
    pvHt= parasail_memalign___m128i(16, segLen);
    pvH = parasail_memalign___m128i(16, segLen);
    pvGapper = parasail_memalign___m128i(16, segLen);

    /* validate heap variables */
    if (!pvE) return NULL;
    if (!boundary) return NULL;
    if (!pvHt) return NULL;
    if (!pvH) return NULL;
    if (!pvGapper) return NULL;

    /* initialize H and E */
    {
        int32_t index = 0;
        for (i=0; i<segLen; ++i) {
            int32_t segNum = 0;
            __m128i_64_t h;
            __m128i_64_t e;
            for (segNum=0; segNum<segWidth; ++segNum) {
                int64_t tmp = -open-gap*(segNum*segLen+i);
                h.v[segNum] = tmp < INT64_MIN ? INT64_MIN : tmp;
                tmp = tmp - open;
                e.v[segNum] = tmp < INT64_MIN ? INT64_MIN : tmp;
            }
            _mm_store_si128(&pvH[index], h.m);
            _mm_store_si128(&pvE[index], e.m);
            ++index;
        }
    }

    /* initialize uppder boundary */
    {
        boundary[0] = 0;
        for (i=1; i<=s2Len; ++i) {
            int64_t tmp = -open-gap*(i-1);
            boundary[i] = tmp < INT64_MIN ? INT64_MIN : tmp;
        }
    }

    {
        __m128i vGapper = _mm_sub_epi64(vZero,vGapO);
        for (i=segLen-1; i>=0; --i) {
            _mm_store_si128(pvGapper+i, vGapper);
            vGapper = _mm_sub_epi64(vGapper, vGapE);
        }
    }

    /* outer loop over database sequence */
    for (j=0; j<s2Len; ++j) {
        __m128i vE;
        __m128i vHt;
        __m128i vF;
        __m128i vH;
        __m128i vHp;
        __m128i *pvW;
        __m128i vW;

        /* calculate E */
        /* calculate Ht */
        /* calculate F and H first pass */
        vHp = _mm_load_si128(pvH+(segLen-1));
        vHp = _mm_slli_si128(vHp, 8);
        vHp = _mm_insert_epi64_rpl(vHp, boundary[j], 0);
        pvW = pvP + matrix->mapper[(unsigned char)s2[j]]*segLen;
        vHt = _mm_sub_epi64(vNegLimit, pvGapper[0]);
        vF = vNegLimit;
        for (i=0; i<segLen; ++i) {
            vH = _mm_load_si128(pvH+i);
            vE = _mm_load_si128(pvE+i);
            vW = _mm_load_si128(pvW+i);
            vE = _mm_max_epi64_rpl(
                    _mm_sub_epi64(vE, vGapE),
                    _mm_sub_epi64(vH, vGapO));
            vHp = _mm_add_epi64(vHp, vW);
            vF = _mm_max_epi64_rpl(vF, _mm_add_epi64(vHt, pvGapper[i]));
            vHt = _mm_max_epi64_rpl(vE, vHp);
            _mm_store_si128(pvE+i, vE);
            _mm_store_si128(pvHt+i, vHt);
            vHp = vH;
        }

        /* pseudo prefix scan on F and H */
        vHt = _mm_slli_si128(vHt, 8);
        vHt = _mm_insert_epi64_rpl(vHt, boundary[j+1], 0);
        vF = _mm_max_epi64_rpl(vF, _mm_add_epi64(vHt, pvGapper[0]));
        for (i=0; i<segWidth-2; ++i) {
            __m128i vFt = _mm_slli_si128(vF, 8);
            vFt = _mm_add_epi64(vFt, vSegLenXgap);
            vF = _mm_max_epi64_rpl(vF, vFt);
        }

        /* calculate final H */
        vF = _mm_slli_si128(vF, 8);
        vF = _mm_add_epi64(vF, vNegInfFront);
        vH = _mm_max_epi64_rpl(vHt, vF);
        for (i=0; i<segLen; ++i) {
            vHt = _mm_load_si128(pvHt+i);
            vF = _mm_max_epi64_rpl(
                    _mm_sub_epi64(vF, vGapE),
                    _mm_sub_epi64(vH, vGapO));
            vH = _mm_max_epi64_rpl(vHt, vF);
            _mm_store_si128(pvH+i, vH);
            vSaturationCheckMin = _mm_min_epi64_rpl(vSaturationCheckMin, vH);
            vSaturationCheckMax = _mm_max_epi64_rpl(vSaturationCheckMax, vH);
#ifdef PARASAIL_TABLE
            arr_store_si128(result->tables->score_table, vH, i, segLen, j, s2Len);
#endif
        } 


#ifdef PARASAIL_ROWCOL
        /* extract last value from the column */
        {
            vH = _mm_load_si128(pvH + offset);
            for (k=0; k<position; ++k) {
                vH = _mm_slli_si128(vH, 8);
            }
            result->rowcols->score_row[j] = (int64_t) _mm_extract_epi64_rpl (vH, 1);
        }
#endif
    }

#ifdef PARASAIL_ROWCOL
    for (i=0; i<segLen; ++i) {
        __m128i vH = _mm_load_si128(pvH+i);
        arr_store_col(result->rowcols->score_col, vH, i, segLen);
    }
#endif

    /* extract last value from the last column */
    {
        __m128i vH = _mm_load_si128(pvH + offset);
        for (k=0; k<position; ++k) {
            vH = _mm_slli_si128(vH, 8);
        }
        score = (int64_t) _mm_extract_epi64_rpl (vH, 1);
    }

    if (_mm_movemask_epi8(_mm_or_si128(
            _mm_cmplt_epi64_rpl(vSaturationCheckMin, vNegLimit),
            _mm_cmpgt_epi64_rpl(vSaturationCheckMax, vPosLimit)))) {
        result->flag |= PARASAIL_FLAG_SATURATED;
        score = 0;
        end_query = 0;
        end_ref = 0;
    }

    result->score = score;
    result->end_query = end_query;
    result->end_ref = end_ref;

    parasail_free(pvGapper);
    parasail_free(pvH);
    parasail_free(pvHt);
    parasail_free(boundary);
    parasail_free(pvE);

    return result;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x68, %rsp
movq %rsi, 0x40(%rsp)
testq %rdi, %rdi
je 0x448eeb
movq 0x60(%rdi), %rax
movq %rax, 0x60(%rsp)
testq %rax, %rax
je 0x448ef2
movq 0x10(%rdi), %rax
movq %rax, 0x38(%rsp)
testq %rax, %rax
je 0x448ef9
movl 0x8(%rdi), %edi
testl %edi, %edi
jle 0x448f00
cmpq $0x0, 0x40(%rsp)
je 0x448f07
movl %edx, %r9d
testl %edx, %edx
jle 0x448f0e
testl %ecx, %ecx
js 0x448f15
testl %r8d, %r8d
js 0x448f1c
movl %r8d, 0x2c(%rsp)
leal -0x1(%rdi), %ebp
incq %rdi
movq %rdi, %r12
shrq %r12
movl %ebp, %eax
xorl %edx, %edx
divl %r12d
movl %eax, %r13d
movl %edx, %r15d
movl %ecx, %ebx
negl %ecx
movq 0x38(%rsp), %rdx
movslq 0x20(%rdx), %rax
movq %rbx, %rsi
btsq $0x3f, %rsi
movabsq $-0x8000000000000000, %r14 # imm = 0x8000000000000000
subq %rax, %r14
movl %ecx, 0x10(%rsp)
cmpl %ecx, %eax
cmovgq %rsi, %r14
movslq 0x1c(%rdx), %rax
movq %rax, 0x50(%rsp)
andl $0x7ffffffe, %edi       # imm = 0x7FFFFFFE
movl %r9d, %esi
movq %r9, (%rsp)
callq 0x20ac53
testq %rax, %rax
je 0x448f21
movl %r15d, 0x28(%rsp)
movq %r14, 0x30(%rsp)
movl %ebp, 0x24(%rsp)
movq %rax, 0x58(%rsp)
orl $0x2840401, 0xc(%rax)   # imm = 0x2840401
movl $0x10, %edi
movq %r12, %rsi
callq 0x2f600c
movq %rax, %r14
movq (%rsp), %rax
leal 0x1(%rax), %esi
movl $0x10, %edi
movq %rsi, 0x48(%rsp)
callq 0x20a636
movq %rax, 0x18(%rsp)
movl $0x10, %edi
movq %r12, %rsi
callq 0x2f600c
movq %rax, %rbp
movl $0x10, %edi
movq %r12, %rsi
callq 0x2f600c
movq %rax, %r15
movl $0x10, %edi
movq %r12, %rsi
callq 0x2f600c
testq %r14, %r14
sete %cl
cmpq $0x0, 0x18(%rsp)
sete %dl
orb %cl, %dl
testq %rbp, %rbp
sete %cl
testq %r15, %r15
sete %sil
orb %cl, %sil
orb %dl, %sil
testq %rax, %rax
sete %cl
orb %sil, %cl
jne 0x448f21
movq (%rsp), %rcx
decl %ecx
movl %ecx, 0xc(%rsp)
movq %rbx, %xmm0
pshufd $0x44, %xmm0, %xmm2     # xmm2 = xmm0[0,1,0,1]
movl 0x2c(%rsp), %edx
movd %edx, %xmm0
pshufd $0x44, %xmm0, %xmm4     # xmm4 = xmm0[0,1,0,1]
movq 0x30(%rsp), %rcx
incq %rcx
movabsq $-0x8000000000000000, %rsi # imm = 0x8000000000000000
subq 0x50(%rsp), %rsi
addq $-0x2, %rsi
movq %rcx, %xmm5
pshufd $0x44, %xmm5, %xmm6     # xmm6 = xmm5[0,1,0,1]
movq %rsi, %xmm1
pshufd $0x44, %xmm1, %xmm3     # xmm3 = xmm1[0,1,0,1]
movl %edx, %edi
movslq 0x10(%rsp), %r8
movq %r12, %rcx
imulq %rdi, %rcx
negq %rcx
movq %rcx, %rsi
subq %rbx, %rsi
negq %rbx
movq %r12, 0x10(%rsp)
movq %r12, %rdx
shlq $0x4, %rdx
xorl %r9d, %r9d
movq %r8, %r10
leaq (%rbx,%r10), %r11
leaq (%rcx,%r10), %r12
movq %r12, %xmm0
movq %r10, %xmm7
punpcklqdq %xmm0, %xmm7    # xmm7 = xmm7[0],xmm0[0]
leaq (%rsi,%r10), %r12
movq %r12, %xmm0
movq %r11, %xmm8
punpcklqdq %xmm0, %xmm8    # xmm8 = xmm8[0],xmm0[0]
movdqa %xmm7, (%r15,%r9)
movdqa %xmm8, (%r14,%r9)
subq %rdi, %r10
addq $0x10, %r9
cmpq %r9, %rdx
jne 0x448b04
movq 0x18(%rsp), %r11
movq $0x0, (%r11)
movl (%rsp), %esi
movq 0x48(%rsp), %rbx
andl $-0x2, %ebx
leaq -0x1(%rsi), %rcx
movq %rcx, %xmm0
pshufd $0x44, %xmm0, %xmm0     # xmm0 = xmm0[0,1,0,1]
movq %rdi, %rcx
negq %rcx
addq %rdi, %rdi
xorl %r9d, %r9d
pmovsxbq 0x1e42e7(%rip), %xmm7   # 0x62ce66
movdqa 0x1e3108(%rip), %xmm8   # 0x62bc90
pxor %xmm8, %xmm0
pcmpeqd %xmm9, %xmm9
movq %r9, %xmm10
movdqa %xmm10, %xmm11
pxor %xmm8, %xmm11
pcmpgtq %xmm0, %xmm11
movd %xmm11, %r10d
notl %r10d
testb $0x1, %r10b
je 0x448bba
movq %r8, 0x8(%r11,%r9,8)
pshufd $0x44, %xmm10, %xmm10   # xmm10 = xmm10[0,1,0,1]
por %xmm7, %xmm10
pxor %xmm8, %xmm10
pcmpgtq %xmm0, %xmm10
pxor %xmm9, %xmm10
pextrb $0x8, %xmm10, %r10d
testb $0x1, %r10b
je 0x448beb
leaq (%rcx,%r8), %r10
movq %r10, 0x10(%r11,%r9,8)
addq $0x2, %r9
subq %rdi, %r8
cmpq %r9, %rbx
jne 0x448b92
pxor %xmm0, %xmm0
psubq %xmm2, %xmm0
movq 0x10(%rsp), %r10
leal -0x1(%r10), %edi
shlq $0x4, %rdi
movq %rax, %rcx
addq %rdi, %rcx
movl %r10d, %r8d
movdqa %xmm0, (%rcx)
psubq %xmm4, %xmm0
addq $-0x10, %rcx
decl %r8d
jg 0x448c15
addq %r15, %rdi
movl 0x28(%rsp), %r9d
movq %r9, (%rsp)
shlq $0x4, %r9
addq %r15, %r9
xorl %ebx, %ebx
movslq %r10d, %r10
movdqa %xmm6, %xmm7
movq %rbx, %r11
pshufd $0x44, (%rdi), %xmm8    # xmm8 = mem[0,1,0,1]
movq 0x18(%rsp), %r12
pinsrq $0x0, (%r12,%rbx,8), %xmm8
movq 0x38(%rsp), %rcx
movq 0x10(%rcx), %rcx
movq 0x40(%rsp), %r8
movzbl (%r8,%rbx), %ebx
movslq (%rcx,%rbx,4), %rcx
imulq %r10, %rcx
shlq $0x4, %rcx
addq 0x60(%rsp), %rcx
movdqa %xmm6, %xmm9
psubq (%rax), %xmm9
xorl %ebx, %ebx
movdqa %xmm6, %xmm10
movdqa %xmm10, %xmm12
movdqa (%r15,%rbx), %xmm11
movdqa (%r14,%rbx), %xmm13
psubq %xmm4, %xmm13
movdqa %xmm11, %xmm14
paddq (%rcx,%rbx), %xmm8
paddq (%rax,%rbx), %xmm9
psubq %xmm2, %xmm14
movdqa %xmm10, %xmm0
pcmpgtq %xmm9, %xmm0
movdqa %xmm9, %xmm10
blendvpd %xmm0, %xmm12, %xmm10
movdqa %xmm13, %xmm0
pcmpgtq %xmm14, %xmm0
blendvpd %xmm0, %xmm13, %xmm14
movapd %xmm14, %xmm0
pcmpgtq %xmm8, %xmm0
movdqa %xmm8, %xmm9
blendvpd %xmm0, %xmm14, %xmm9
movapd %xmm14, (%r14,%rbx)
movapd %xmm9, (%rbp,%rbx)
addq $0x10, %rbx
movdqa %xmm11, %xmm8
cmpq %rbx, %rdx
jne 0x448c8d
pshufd $0x44, %xmm9, %xmm9     # xmm9 = xmm9[0,1,0,1]
leaq 0x1(%r11), %rbx
movq 0x8(%r12,%r11,8), %rcx
movq (%rax), %r12
addq %rcx, %r12
movq %xmm10, %r8
cmpq %r12, %r8
cmovgq %r8, %r12
movq %r12, %xmm8
pslldq $0x8, %xmm8             # xmm8 = zero,zero,zero,zero,zero,zero,zero,zero,xmm8[0,1,2,3,4,5,6,7]
pinsrq $0x0, %rcx, %xmm9
paddq %xmm5, %xmm8
movdqa %xmm9, %xmm0
pcmpgtq %xmm8, %xmm0
movdqa %xmm8, %xmm10
blendvpd %xmm0, %xmm9, %xmm10
xorl %ecx, %ecx
movdqa %xmm3, %xmm9
psubq %xmm4, %xmm8
psubq %xmm2, %xmm10
movdqa %xmm8, %xmm0
pcmpgtq %xmm10, %xmm0
blendvpd %xmm0, %xmm8, %xmm10
movdqa (%rbp,%rcx), %xmm3
movdqa %xmm3, %xmm0
pcmpgtq %xmm10, %xmm0
movdqa %xmm10, %xmm8
blendvpd %xmm0, %xmm3, %xmm10
movdqa %xmm7, %xmm11
movapd %xmm10, (%r15,%rcx)
movapd %xmm10, %xmm0
pcmpgtq %xmm9, %xmm0
movapd %xmm10, %xmm3
blendvpd %xmm0, %xmm9, %xmm3
movdqa %xmm7, %xmm0
pcmpgtq %xmm10, %xmm0
movapd %xmm10, %xmm7
blendvpd %xmm0, %xmm11, %xmm7
addq $0x10, %rcx
cmpq %rcx, %rdx
jne 0x448d65
movdqa (%r9), %xmm0
testl %r13d, %r13d
movq 0x58(%rsp), %r12
jg 0x448df8
pslldq $0x8, %xmm0             # xmm0 = zero,zero,zero,zero,zero,zero,zero,zero,xmm0[0,1,2,3,4,5,6,7]
testl %r13d, %r13d
js 0x448dee
movq 0x10(%r12), %rcx
movq (%rcx), %rcx
pextrd $0x2, %xmm0, (%rcx,%r11,4)
cmpq %rsi, %rbx
jne 0x448c42
movq 0x10(%rsp), %rsi
shlq $0x2, %rsi
xorl %ecx, %ecx
movdqa (%r15,%rcx,4), %xmm0
movq 0x10(%r12), %rdx
movq 0x8(%rdx), %rdx
movd %xmm0, (%rdx,%rcx)
addq %rcx, %rdx
pextrd $0x2, %xmm0, (%rsi,%rdx)
addq $0x4, %rcx
cmpq %rcx, %rsi
jne 0x448e1c
movq (%rsp), %rcx
shlq $0x4, %rcx
movdqa (%r15,%rcx), %xmm0
testl %r13d, %r13d
jle 0x448e5c
movl 0xc(%rsp), %esi
jmp 0x448e6a
movl 0xc(%rsp), %esi
pslldq $0x8, %xmm0             # xmm0 = zero,zero,zero,zero,zero,zero,zero,zero,xmm0[0,1,2,3,4,5,6,7]
testl %r13d, %r13d
js 0x448e60
movq 0x30(%rsp), %xmm2
pshufd $0x44, %xmm2, %xmm2     # xmm2 = xmm2[0,1,0,1]
pcmpgtq %xmm2, %xmm3
pcmpeqd %xmm2, %xmm2
pxor %xmm3, %xmm2
pshufd $0x44, %xmm1, %xmm1     # xmm1 = xmm1[0,1,0,1]
pcmpgtq %xmm1, %xmm7
por %xmm2, %xmm7
movmskpd %xmm7, %ecx
testl %ecx, %ecx
je 0x448ea6
orb $0x40, 0xc(%r12)
xorl %ecx, %ecx
xorl %esi, %esi
xorl %edx, %edx
jmp 0x448eb1
pextrq $0x1, %xmm0, %rcx
movl 0x24(%rsp), %edx
movl %ecx, (%r12)
movl %edx, 0x4(%r12)
movl %esi, 0x8(%r12)
movq %rax, %rdi
callq 0x20a60d
movq %r15, %rdi
callq 0x20a60d
movq %rbp, %rdi
callq 0x20a60d
movq 0x18(%rsp), %rdi
callq 0x20a60d
movq %r14, %rdi
callq 0x20a60d
jmp 0x448f24
callq 0x1d13a1
jmp 0x448f21
callq 0x1d137b
jmp 0x448f21
callq 0x1d1355
jmp 0x448f21
callq 0x1d132f
jmp 0x448f21
callq 0x1d1309
jmp 0x448f21
callq 0x1d12e3
jmp 0x448f21
callq 0x1d12bd
jmp 0x448f21
callq 0x1d1297
xorl %r12d, %r12d
movq %r12, %rax
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop