// File: /workspace/github_c_makefile_star2_O3/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, 0xc(%rsp)
movq %r8, 0x20(%rsp)
movq %rdx, %rbx
movl %esi, %r15d
movb 0xc0(%rsp), %al
movb %al, 0x28(%rsp)
movq 0xe0(%rsp), %rdx
movl 0xd8(%rsp), %eax
movl %eax, 0x48(%rsp)
movl 0xd0(%rsp), %eax
movsbl 0xc8(%rsp), %esi
movq %rsi, 0x50(%rsp)
movaps 0x3cb87a(%rip), %xmm0   # 0x5ca150
movups %xmm0, 0x10(%rdx)
movl $0x0, 0x24(%rdx)
movdqa 0x3cb877(%rip), %xmm0   # 0x5ca160
movq %rdx, 0x30(%rsp)
movdqu %xmm0, (%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, 0x38(%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, 0x68(%rsp)
callq 0x1fbc89
movq %rax, 0x60(%rsp)
addq $0xf, %rax
andq $-0x10, %rax
movslq %r12d, %r13
movq %r13, %r12
shlq $0x4, %r12
movq %rax, 0x10(%rsp)
addq %r12, %rax
movq %rax, 0x18(%rsp)
leaq (%rax,%r12), %rbp
leaq (%r12,%rbp), %rdi
andl $-0x10, %r14d
movslq %r14d, %rax
movq %rax, 0x58(%rsp)
testl %r15d, %r15d
jle 0x1fe99e
movq 0x58(%rsp), %rax
addq %rdi, %rax
movl %r15d, %ecx
movb -0x1(%rbx,%rcx), %dl
movb %dl, (%rax)
incq %rax
decq %rcx
jne 0x1fe990
movq 0x38(%rsp), %rbx
movslq %ebx, %rdx
movq 0x20(%rsp), %rsi
callq 0x19e0c0
leal (%rbx,%r15), %edx
decl %edx
testl %edx, %edx
movl %edx, 0x44(%rsp)
jle 0x1fecab
movb 0x28(%rsp), %cl
movl %ecx, %eax
sarb $0x7, %al
xorb %al, %cl
subb %cl, %al
movq 0x50(%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 0xc(%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
movq %rbx, 0x38(%rsp)
leal (%rcx,%rcx), %eax
movl %eax, 0x4c(%rsp)
movslq %r15d, %rax
movq %rax, 0x28(%rsp)
movl %edx, %eax
movq %rax, 0x70(%rsp)
leaq (,%r13,2), %rax
addq %r13, %rax
shlq $0x4, %rax
addq 0x10(%rsp), %rax
movq %rax, 0x78(%rsp)
decl %r15d
shlq $0x5, %r13
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
pxor %xmm3, %xmm3
xorl %r8d, %r8d
movl $0xffffffff, 0xc(%rsp)  # imm = 0xFFFFFFFF
xorl %eax, %eax
xorl %r10d, %r10d
movq 0x30(%rsp), %r14
movl %eax, 0x20(%rsp)
movq %r8, %rcx
subq 0x28(%rsp), %rcx
leal 0x1(%rcx), %edx
testq %rcx, %rcx
movl $0x0, %ecx
cmovsl %ecx, %edx
movq 0x38(%rsp), %rsi
cmpl %r8d, %esi
movl %r8d, %ecx
cmovll %esi, %ecx
movl %r8d, %r9d
movq 0x80(%rsp), %rsi
subl %esi, %r9d
incl %r9d
sarl %r9d
cmpl %r9d, %edx
movl %r9d, %edi
cmovgl %edx, %edi
leal (%rsi,%r8), %r11d
sarl %r11d
cmpl %r11d, %ecx
cmovll %ecx, %r11d
cmpl %r11d, %edi
jg 0x1fecb7
movl %ebx, %eax
xorl %r14d, %r14d
movl %edi, %ebx
andl $-0x10, %ebx
jle 0x1feaef
cmpl %eax, %ebx
jle 0x1feaef
leal -0x1(%rbx), %eax
cmpl 0xc(%rsp), %eax
jg 0x1feaef
movl %eax, %eax
movq 0x18(%rsp), %rcx
movzbl (%rcx,%rax), %r14d
movl %r11d, %eax
orl $0xf, %eax
movl %eax, 0xc(%rsp)
cltq
cmpq %rax, %r8
jg 0x1feb0a
movq 0x10(%rsp), %rax
movb $0x0, (%rax,%r8)
movslq %r15d, %rcx
addq 0x58(%rsp), %rcx
movl %edi, %esi
shrl $0x4, %esi
movl %r11d, %eax
shrl $0x4, %eax
cmpl %r9d, %edx
cmovgl %edx, %r9d
movd %r14d, %xmm4
movslq %r9d, %rdx
movslq %r11d, %r9
movq 0x78(%rsp), %r14
addq %rdx, %r14
movdqu (%r14), %xmm5
movdqu (%r14,%rcx), %xmm6
pcmpeqb %xmm5, %xmm6
movdqa %xmm1, %xmm5
pand %xmm6, %xmm5
pandn %xmm2, %xmm6
por %xmm5, %xmm6
movdqu %xmm6, (%rbp,%rdx)
addq $0x10, %rdx
addq $0x10, %r14
cmpq %r9, %rdx
jle 0x1feb37
cmpl %eax, %esi
ja 0x1febea
movl %eax, %edx
decq %rsi
movl %edi, %r9d
andl $-0x10, %r9d
addq 0x10(%rsp), %r9
movdqa (%r9,%r13), %xmm5
paddb %xmm0, %xmm5
movdqa (%r9,%r12), %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 (%r9), %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, (%r9)
psubb %xmm4, %xmm5
movdqa %xmm5, (%r9,%r12)
incq %rsi
addq $0x10, %r9
movdqa %xmm7, %xmm4
cmpq %rdx, %rsi
jb 0x1feb7e
testq %r8, %r8
movq 0x30(%rsp), %r14
je 0x1fec2b
cmpl %r11d, %r10d
jg 0x1fec3c
cmpl %edi, %r10d
jl 0x1fec3c
movl %r10d, %eax
cmpl %r11d, %r10d
jge 0x1fec4e
leaq 0x1(%rax), %rcx
movq 0x18(%rsp), %rdx
movzbl (%rdx,%rax), %edx
movq 0x10(%rsp), %rsi
movzbl 0x1(%rsi,%rax), %eax
cmpb %al, %dl
cmoval %r10d, %ecx
cmoval %edx, %eax
movl %ecx, %r10d
jmp 0x1fec56
movq 0x18(%rsp), %rax
movzbl (%rax), %esi
subl 0x4c(%rsp), %esi
xorl %r10d, %r10d
jmp 0x1fec96
movslq %r10d, %r10
movq 0x10(%rsp), %rax
movb 0x1(%rax,%r10), %al
incq %r10
jmp 0x1fec56
movq 0x18(%rsp), %rcx
movb (%rcx,%rax), %al
movzbl %al, %esi
subl 0x50(%rsp), %esi
addl 0x20(%rsp), %esi
movl (%r14), %eax
movl %eax, %ecx
andl $0x7fffffff, %ecx       # imm = 0x7FFFFFFF
subl %esi, %ecx
jge 0x1fec8a
andl $0x80000000, %eax       # imm = 0x80000000
orl %esi, %eax
movl %eax, (%r14)
movl %r10d, 0x8(%r14)
movl %r8d, %eax
subl %r10d, %eax
movl %eax, 0x4(%r14)
jmp 0x1fec96
movl 0x48(%rsp), %eax
testl %eax, %eax
js 0x1fec96
cmpl %eax, %ecx
jg 0x1fecbb
incq %r8
decl %r15d
movl %esi, %eax
cmpq 0x70(%rsp), %r8
jne 0x1fea6e
jmp 0x1fecc2
xorl %r8d, %r8d
xorl %esi, %esi
movq 0x30(%rsp), %r14
jmp 0x1fecbb
movl 0x20(%rsp), %esi
cmpl 0x44(%rsp), %r8d
jne 0x1fecc8
movl %esi, 0x1c(%r14)
jmp 0x1feccd
orb $-0x80, 0x3(%r14)
movq 0x68(%rsp), %rdi
movq 0x60(%rsp), %rsi
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1fb9e0
nopl (%rax)