// File: /workspace/github_c_makefile_star2_O1/nh13[P]ksw/src/ksw2/ksw2_extf2_sse.c
// Function: ksw_extf2_sse
void ksw_extf2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t mch, int8_t mis, int8_t e, int w, int xdrop, ksw_extz_t *ez)
{
	int32_t r, t, tlen_, qlen_, last_st, last_en, H0 = 0, last_H0_t = 0;
	uint8_t *qr, *sf, *mem;
	__m128i e2_, sc_mch_, sc_mis_, *u, *v, *s;

	ksw_reset_extz(ez);
	e2_ = _mm_set1_epi8(e * 2);
	sc_mch_ = _mm_set1_epi8(mch);
	sc_mis_ = _mm_set1_epi8(mis < 0? mis : -mis);
	tlen_ = (tlen + 15) / 16;
	qlen_ = (qlen + 15) / 16;
	if (w < 0) w = tlen > qlen? tlen : qlen;

	mem = (uint8_t*)kcalloc(km, tlen_ * 4 + qlen_ + 1, 16);
	u = (__m128i*)(((size_t)mem + 15) >> 4 << 4); // 16-byte aligned
	v = u + tlen_, s = v + tlen_, sf = (uint8_t*)(s + tlen_), qr = sf + tlen_ * 16;

	for (t = 0; t < qlen; ++t) qr[t] = query[qlen - 1 - t];
	memcpy(sf, target, tlen);

	for (r = 0, last_st = last_en = -1; r < qlen + tlen - 1; ++r) {
		int st = 0, en = tlen - 1, st0, en0, st_, en_;
		uint8_t v1, *qrr = qr + (qlen - 1 - r), *u8 = (uint8_t*)u, *v8 = (uint8_t*)v;
		__m128i v1_;
		// find the boundaries
		if (st < r - qlen + 1) st = r - qlen + 1;
		if (en > r) en = r;
		if (st < (r-w+1)>>1) st = (r-w+1)>>1; // take the ceil
		if (en > (r+w)>>1) en = (r+w)>>1; // take the floor
		if (st > en) break;
		st0 = st, en0 = en;
		st = st / 16 * 16, en = (en + 16) / 16 * 16 - 1;
		// set boundary conditions
		v1 = (st > 0 && st - 1 >= last_st && st - 1 <= last_en)? v8[st - 1] : 0;
		if (en >= r) u8[r] = 0;
		// core loop
		v1_ = _mm_cvtsi32_si128(v1);
		st_ = st / 16, en_ = en / 16;
		for (t = st0; t <= en0; t += 16) {
			__m128i sq, st, tmp;
			sq = _mm_loadu_si128((__m128i*)&sf[t]);
			st = _mm_loadu_si128((__m128i*)&qrr[t]);
			tmp = _mm_cmpeq_epi8(sq, st);
#ifdef __SSE4_1__
			tmp = _mm_blendv_epi8(sc_mis_, sc_mch_, tmp);
#else
			tmp = _mm_or_si128(_mm_andnot_si128(tmp, sc_mis_), _mm_and_si128(tmp, sc_mch_));
#endif
			_mm_storeu_si128((__m128i*)((uint8_t*)s + t), tmp);
		}
		for (t = st_; t <= en_; ++t) {
			__m128i z, vt1, ut, tmp;
			z = _mm_add_epi8(_mm_load_si128(&s[t]), e2_);
			vt1 = _mm_load_si128(&v[t]);                     // vt1 <- v[r-1][t..t+15]
			tmp = _mm_srli_si128(vt1, 15);                   // tmp <- v[r-1][t+15]
			vt1 = _mm_or_si128(_mm_slli_si128(vt1, 1), v1_); // vt1 <- v[r-1][t-1..t+14]
			v1_ = tmp;
			ut = _mm_load_si128(&u[t]);                      // ut <- u[t..t+15]
#ifdef __SSE4_1__
			z = _mm_max_epi8(z, vt1);                        // z = z > a? z : a (signed)
#else
			z = _mm_and_si128(z, _mm_cmpgt_epi8(z, _mm_setzero_si128()));  // z = z > 0? z : 0;
			z = _mm_max_epu8(z, vt1);                        // z = max(z, a); this works because both are non-negative
#endif
			z = _mm_max_epu8(z, ut);                         // z = max(z, b); this works because both are non-negative
			_mm_store_si128(&u[t], _mm_sub_epi8(z, vt1));    // u[r][t..t+15] <- z - v[r-1][t-1..t+14]
			_mm_store_si128(&v[t], _mm_sub_epi8(z, ut));     // v[r][t..t+15] <- z - u[r-1][t..t+15]
		}
		if (r > 0) {
			if (last_H0_t >= st0 && last_H0_t <= en0 && last_H0_t + 1 >= st0 && last_H0_t + 1 <= en0) {
				int32_t d0 = v8[last_H0_t] - e, d1 = u8[last_H0_t + 1] - e;
				if (d0 > d1) H0 += d0;
				else H0 += d1, ++last_H0_t;
			} else if (last_H0_t >= st0 && last_H0_t <= en0) {
				H0 += v8[last_H0_t] - e;
			} else {
				++last_H0_t, H0 += u8[last_H0_t] - e;
			}
			if (H0 > ez->max) ez->max = H0, ez->max_t = last_H0_t, ez->max_q = r - last_H0_t;
			else if (xdrop >= 0 && ez->max - H0 > xdrop) break;
		} else H0 = v8[0] - e - e, last_H0_t = 0;
		last_st = st, last_en = en;
	}
	if (r == qlen + tlen - 1) ez->score = H0;
	else ez->zdropped = 1;
	kfree(km, mem);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x88, %rsp
movl %r9d, 0x38(%rsp)
movq %r8, 0x18(%rsp)
movq %rdx, %rbx
movl %esi, %r15d
movb 0xc0(%rsp), %al
movb %al, 0x30(%rsp)
movq 0xe0(%rsp), %rdx
movl 0xd8(%rsp), %eax
movl %eax, 0x48(%rsp)
movl 0xd0(%rsp), %eax
movsbl 0xc8(%rsp), %esi
movq %rsi, 0x60(%rsp)
movabsq $-0x3fffffff00000001, %rsi # imm = 0xC0000000FFFFFFFF
movq %rsi, 0x18(%rdx)
movq %rsi, 0x10(%rdx)
movq %rsi, 0x8(%rdx)
movl $0x0, 0x24(%rdx)
movabsq $-0x100000000, %rsi     # imm = 0xFFFFFFFF00000000
movq %rdx, 0x68(%rsp)
movq %rsi, (%rdx)
leal 0xf(%rcx), %edx
leal 0x1e(%rcx), %r14d
testl %edx, %edx
cmovnsl %edx, %r14d
movl %r14d, %r12d
sarl $0x4, %r12d
leal 0xf(%r15), %esi
leal 0x1e(%r15), %edx
testl %esi, %esi
cmovnsl %esi, %edx
sarl $0x4, %edx
cmpl %r15d, %ecx
movl %r15d, %esi
movq %rcx, 0x20(%rsp)
cmovgl %ecx, %esi
testl %eax, %eax
cmovnsl %eax, %esi
movq %rsi, 0x80(%rsp)
leal 0x1(%rdx,%r12,4), %eax
movslq %eax, %rsi
movl $0x10, %edx
movq %rdi, 0x50(%rsp)
callq 0x1fbc8d
movq %rax, 0x70(%rsp)
addq $0xf, %rax
andq $-0x10, %rax
movslq %r12d, %r12
movq %r12, %r13
shlq $0x4, %r13
movq %rax, (%rsp)
addq %r13, %rax
movq %rax, 0x10(%rsp)
leaq (%rax,%r13), %rbp
movq %rbp, %rdi
addq %r13, %rdi
andl $-0x10, %r14d
movslq %r14d, %rax
movq %rax, 0x58(%rsp)
testl %r15d, %r15d
jle 0x1fe92f
movq 0x58(%rsp), %rax
addq %rdi, %rax
movl %r15d, %ecx
movb -0x1(%rbx,%rcx), %dl
movb %dl, (%rax)
incq %rax
decq %rcx
jne 0x1fe921
movq 0x20(%rsp), %rbx
movslq %ebx, %rdx
movq 0x18(%rsp), %rsi
callq 0x19e0c0
leal (%rbx,%r15), %edx
decl %edx
testl %edx, %edx
jle 0x1fec72
movb 0x30(%rsp), %cl
movl %ecx, %eax
sarb $0x7, %al
xorb %al, %cl
subb %cl, %al
movq 0x60(%rsp), %rcx
movd %ecx, %xmm0
movzbl %al, %eax
punpcklbw %xmm0, %xmm0    # xmm0 = xmm0[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
movd 0x38(%rsp), %xmm1
movd %eax, %xmm2
pshuflw $0x0, %xmm0, %xmm0      # xmm0 = xmm0[0,0,0,0,4,5,6,7]
punpcklbw %xmm1, %xmm1    # xmm1 = xmm1[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
punpcklbw %xmm2, %xmm2    # xmm2 = xmm2[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
pshufd $0x0, %xmm0, %xmm0      # xmm0 = xmm0[0,0,0,0]
pshuflw $0x0, %xmm1, %xmm1      # xmm1 = xmm1[0,0,0,0,4,5,6,7]
pshuflw $0x0, %xmm2, %xmm2      # xmm2 = xmm2[0,0,0,0,4,5,6,7]
paddb %xmm0, %xmm0
pshufd $0x0, %xmm1, %xmm1      # xmm1 = xmm1[0,0,0,0]
pshufd $0x0, %xmm2, %xmm2      # xmm2 = xmm2[0,0,0,0]
decl %ebx
leal (%rcx,%rcx), %eax
movl %eax, 0x44(%rsp)
movslq %r15d, %rax
movq %rax, 0x38(%rsp)
movl %edx, 0xc(%rsp)
movl %edx, %eax
movq %rax, 0x30(%rsp)
leaq (%r12,%r12,2), %rax
shlq $0x4, %rax
addq (%rsp), %rax
movq %rax, 0x78(%rsp)
decl %r15d
shlq $0x5, %r12
movl $0xffffffff, %r11d      # imm = 0xFFFFFFFF
pxor %xmm3, %xmm3
xorl %edi, %edi
movl $0xffffffff, %r8d       # imm = 0xFFFFFFFF
xorl %r9d, %r9d
xorl %r14d, %r14d
movq %rbx, 0x20(%rsp)
movq %r14, 0x18(%rsp)
movq %rdi, %rax
subq 0x38(%rsp), %rax
leal 0x1(%rax), %r14d
testq %rax, %rax
movl $0x0, %eax
cmovsl %eax, %r14d
cmpl %edi, %ebx
movl %edi, %eax
cmovll %ebx, %eax
movq 0x80(%rsp), %rdx
leal (%rdx,%rdi), %ecx
movl %edi, %esi
subl %edx, %esi
incl %esi
sarl %esi
cmpl %esi, %r14d
movl %esi, %r10d
cmovgl %r14d, %r10d
sarl %ecx
cmpl %ecx, %eax
cmovll %eax, %ecx
xorl %edx, %edx
cmpl %ecx, %r10d
jle 0x1fea53
movl %r9d, %ecx
movl %r8d, %eax
movl %r11d, %esi
movq 0x18(%rsp), %r14
jmp 0x1fec3c
movl %r10d, %eax
andl $-0x10, %eax
movq %rax, 0x28(%rsp)
jle 0x1fea77
cmpl %r11d, %eax
jle 0x1fea77
decl %eax
cmpl %r8d, %eax
jg 0x1fea77
movl %eax, %eax
movq 0x10(%rsp), %rdx
movzbl (%rdx,%rax), %edx
movl %edx, 0x4c(%rsp)
movl %ecx, %eax
orl $0xf, %eax
movslq %eax, %rdx
cmpq %rdx, %rdi
jg 0x1fea90
movq (%rsp), %rdx
movb $0x0, (%rdx,%rdi)
cmpl %ecx, %r10d
jg 0x1feae2
movslq %r15d, %rdx
addq 0x58(%rsp), %rdx
cmpl %esi, %r14d
cmovgl %r14d, %esi
movslq %esi, %rsi
movslq %ecx, %r14
movq 0x78(%rsp), %rbx
addq %rsi, %rbx
movdqu (%rbx), %xmm4
movdqu (%rbx,%rdx), %xmm5
pcmpeqb %xmm4, %xmm5
movdqa %xmm1, %xmm4
pand %xmm5, %xmm4
pandn %xmm2, %xmm5
por %xmm4, %xmm5
movdqu %xmm5, (%rbp,%rsi)
addq $0x10, %rsi
addq $0x10, %rbx
cmpq %r14, %rsi
jle 0x1feab2
movl %r10d, %esi
shrl $0x4, %esi
movl %ecx, %edx
shrl $0x4, %edx
cmpl %edx, %esi
ja 0x1feb77
movd 0x4c(%rsp), %xmm4
movl %edx, %edx
decq %rsi
movl %r10d, %r14d
andl $-0x10, %r14d
addq (%rsp), %r14
movdqa (%r14,%r12), %xmm5
paddb %xmm0, %xmm5
movdqa (%r14,%r13), %xmm6
movdqa %xmm6, %xmm7
psrldq $0xf, %xmm7             # xmm7 = xmm7[15],zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero
pslldq $0x1, %xmm6             # xmm6 = zero,xmm6[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
por %xmm4, %xmm6
movdqa (%r14), %xmm4
movdqa %xmm5, %xmm8
pcmpgtb %xmm3, %xmm8
pand %xmm5, %xmm8
movdqa %xmm6, %xmm5
pmaxub %xmm4, %xmm5
pmaxub %xmm8, %xmm5
movdqa %xmm5, %xmm8
psubb %xmm6, %xmm8
movdqa %xmm8, (%r14)
psubb %xmm4, %xmm5
movdqa %xmm5, (%r14,%r13)
incq %rsi
addq $0x10, %r14
movdqa %xmm7, %xmm4
cmpq %rdx, %rsi
jb 0x1feb0b
testq %rdi, %rdi
movq 0x20(%rsp), %rbx
je 0x1feba9
movq 0x18(%rsp), %r14
cmpl %r10d, %r14d
setl %sil
cmpl %ecx, %r14d
setg %dl
orb %sil, %dl
je 0x1febba
movslq %r14d, %r14
movq (%rsp), %rcx
movb 0x1(%rcx,%r14), %cl
incq %r14
jmp 0x1febf7
movq 0x10(%rsp), %rcx
movzbl (%rcx), %ecx
subl 0x44(%rsp), %ecx
xorl %r14d, %r14d
jmp 0x1fec35
cmpl %ecx, %r14d
jge 0x1febe8
movl %r14d, %ecx
leaq 0x1(%rcx), %rdx
movq 0x10(%rsp), %rsi
movzbl (%rsi,%rcx), %esi
movq (%rsp), %r10
movzbl 0x1(%r10,%rcx), %ecx
cmpb %cl, %sil
cmoval %r14d, %edx
cmoval %esi, %ecx
movl %edx, %r14d
jmp 0x1febf7
testb %dl, %dl
jne 0x1feb98
movl %r14d, %ecx
movq 0x10(%rsp), %rdx
movb (%rdx,%rcx), %cl
movzbl %cl, %ecx
subl 0x60(%rsp), %ecx
addl %r9d, %ecx
movq 0x68(%rsp), %r9
movl (%r9), %edx
movl %edx, %esi
andl $0x7fffffff, %esi       # imm = 0x7FFFFFFF
subl %ecx, %esi
jge 0x1fec5c
movl %ecx, %esi
andl $0x7fffffff, %esi       # imm = 0x7FFFFFFF
andl $0x80000000, %edx       # imm = 0x80000000
orl %esi, %edx
movl %edx, (%r9)
movl %r14d, 0x8(%r9)
movl %edi, %edx
subl %r14d, %edx
movl %edx, 0x4(%r9)
movb $0x1, %dl
movq 0x28(%rsp), %rsi
testb %dl, %dl
je 0x1fec78
incq %rdi
decl %r15d
movl %esi, %r11d
movl %eax, %r8d
movl %ecx, %r9d
cmpq 0x30(%rsp), %rdi
jne 0x1fe9f1
jmp 0x1fec7e
movl 0x48(%rsp), %edx
testl %edx, %edx
js 0x1fec35
cmpl %edx, %esi
jle 0x1fec35
xorl %edx, %edx
movl %r8d, %eax
movl %r11d, %esi
jmp 0x1fec3c
xorl %edi, %edi
xorl %ecx, %ecx
jmp 0x1fec84
movl 0xc(%rsp), %edx
jmp 0x1fec84
movl 0xc(%rsp), %edx
movl %edx, %edi
cmpl %edx, %edi
movq 0x68(%rsp), %rax
jne 0x1fec92
movl %ecx, 0x1c(%rax)
jmp 0x1fec96
orb $-0x80, 0x3(%rax)
movq 0x50(%rsp), %rdi
movq 0x70(%rsp), %rsi
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1fb9e5
nop