// File: /workspace/github_c_makefile_star2_O2/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 $0xd8, %rsp
movq %r8, 0x28(%rsp)
movq %rdx, %rbp
movl %esi, %r15d
movb 0x110(%rsp), %al
movq 0x130(%rsp), %rbx
movl 0x128(%rsp), %edx
movl %edx, 0xc(%rsp)
movl 0x120(%rsp), %edx
movl %edx, 0x38(%rsp)
movb 0x118(%rsp), %dl
movaps 0x3c7295(%rip), %xmm0   # 0x568150
movups %xmm0, 0x10(%rbx)
andl $0x0, 0x24(%rbx)
movaps 0x3c7296(%rip), %xmm0   # 0x568160
movups %xmm0, (%rbx)
movq %rdx, 0x30(%rsp)
addl %edx, %edx
movzbl %dl, %edx
movd %edx, %xmm0
movdqa %xmm0, 0x70(%rsp)
movd %r9d, %xmm0
movdqa %xmm0, 0x80(%rsp)
movl %eax, %edx
sarb $0x7, %dl
xorb %dl, %al
subb %al, %dl
movzbl %dl, %r8d
leal 0xf(%rcx), %eax
pushq $0x10
popq %rsi
cltd
idivl %esi
movl %eax, %r14d
leal 0xf(%r15), %eax
cltd
idivl %esi
cmpl %r15d, %ecx
movl %r15d, %edx
movq %rcx, 0x48(%rsp)
cmovgl %ecx, %edx
movq %rdx, 0x40(%rsp)
movd %r8d, %xmm0
movdqa %xmm0, 0x60(%rsp)
leal 0x1(%rax,%r14,4), %eax
movslq %eax, %rsi
pushq $0x10
popq %rdx
movq %rdi, 0x58(%rsp)
callq 0x19e66e
movq %rax, 0x50(%rsp)
addq $0xf, %rax
andq $-0x10, %rax
movslq %r14d, %r14
movq %r14, %r12
shlq $0x4, %r12
movq %rax, 0x10(%rsp)
addq %r12, %rax
movq %rax, 0x20(%rsp)
leaq (%rax,%r12), %r13
leaq (%r12,%r13), %rdi
movl %r14d, %eax
shll $0x4, %eax
cltq
movq %rax, 0x98(%rsp)
addq %rdi, %rax
xorl %ecx, %ecx
testl %r15d, %r15d
movl $0x0, %edx
cmovgl %r15d, %edx
movq %r15, 0x18(%rsp)
leal -0x1(%r15), %esi
cmpq %rcx, %rdx
je 0x1a0fb0
movslq %esi, %rsi
movb (%rbp,%rsi), %r8b
movb %r8b, (%rax,%rcx)
incq %rcx
decl %esi
jmp 0x1a0f98
movsbl 0x30(%rsp), %r15d
movdqa 0x70(%rsp), %xmm0
punpcklbw %xmm0, %xmm0    # xmm0 = xmm0[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
pshuflw $0x0, %xmm0, %xmm0      # xmm0 = xmm0[0,0,0,0,4,5,6,7]
pshufd $0x0, %xmm0, %xmm0      # xmm0 = xmm0[0,0,0,0]
movdqa %xmm0, 0xc0(%rsp)
movdqa 0x80(%rsp), %xmm0
punpcklbw %xmm0, %xmm0    # xmm0 = xmm0[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
pshuflw $0x0, %xmm0, %xmm0      # xmm0 = xmm0[0,0,0,0,4,5,6,7]
pshufd $0x0, %xmm0, %xmm0      # xmm0 = xmm0[0,0,0,0]
movdqa %xmm0, 0xb0(%rsp)
movdqa 0x60(%rsp), %xmm0
punpcklbw %xmm0, %xmm0    # xmm0 = xmm0[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
pshuflw $0x0, %xmm0, %xmm0      # xmm0 = xmm0[0,0,0,0,4,5,6,7]
pshufd $0x0, %xmm0, %xmm0      # xmm0 = xmm0[0,0,0,0]
movdqa %xmm0, 0xa0(%rsp)
movl 0x38(%rsp), %ecx
testl %ecx, %ecx
movq 0x40(%rsp), %rax
cmovnsl %ecx, %eax
movq %rax, 0x40(%rsp)
movq 0x48(%rsp), %rbp
movslq %ebp, %rdx
movq 0x28(%rsp), %rsi
callq 0x19e0c0
movdqa 0xa0(%rsp), %xmm8
movdqa 0xb0(%rsp), %xmm7
movdqa 0xc0(%rsp), %xmm6
movl %ebp, %eax
decl %ebp
movq %rbp, 0x48(%rsp)
movq 0x18(%rsp), %rdx
addl %edx, %eax
decl %eax
movq %r15, 0x80(%rsp)
leal (%r15,%r15), %ecx
movl %ecx, 0x70(%rsp)
movslq %edx, %rcx
movq %rcx, 0x38(%rsp)
testl %eax, %eax
movl $0x0, %ecx
movl %eax, 0x60(%rsp)
cmovgl %eax, %ecx
movq %rcx, 0x28(%rsp)
imulq $0x30, %r14, %rax
addq 0x10(%rsp), %rax
movq %rax, 0x30(%rsp)
decl %edx
movq %rdx, 0x18(%rsp)
shlq $0x5, %r14
pushq $-0x1
popq %rsi
pxor %xmm0, %xmm0
xorl %r9d, %r9d
xorl %r10d, %r10d
xorl %r15d, %r15d
movl %esi, %eax
cmpq 0x28(%rsp), %r9
je 0x1a12f1
movl %eax, %edi
movq %r9, %rax
subq 0x38(%rsp), %rax
leal 0x1(%rax), %edx
testq %rax, %rax
movl $0x0, %eax
cmovsl %eax, %edx
movq 0x48(%rsp), %rcx
cmpl %r9d, %ecx
movl %r9d, %eax
cmovll %ecx, %eax
movl %r9d, %ebp
movq 0x40(%rsp), %rcx
subl %ecx, %ebp
incl %ebp
sarl %ebp
cmpl %ebp, %edx
movl %ebp, %r8d
cmovgl %edx, %r8d
leal (%rcx,%r9), %r11d
sarl %r11d
cmpl %r11d, %eax
cmovll %eax, %r11d
cmpl %r11d, %r8d
jg 0x1a12f6
movq %rbx, %rcx
xorl %ebx, %ebx
movl %r8d, %eax
andl $-0x10, %eax
jle 0x1a113b
cmpl %edi, %eax
jle 0x1a113b
leal -0x1(%rax), %edi
cmpl %esi, %edi
jg 0x1a113b
movl %edi, %esi
movq 0x20(%rsp), %rdi
movzbl (%rdi,%rsi), %ebx
movl %r11d, %esi
orl $0xf, %esi
movslq %esi, %rdi
cmpq %rdi, %r9
jg 0x1a1153
movq 0x10(%rsp), %rdi
movb $0x0, (%rdi,%r9)
movslq 0x18(%rsp), %rdi
addq 0x98(%rsp), %rdi
cmpl %ebp, %edx
cmovgl %edx, %ebp
movd %ebx, %xmm1
movslq %ebp, %rdx
movslq %r11d, %rbx
movq 0x30(%rsp), %rbp
addq %rdx, %rbp
cmpq %rbx, %rdx
jg 0x1a11ad
movdqu (%rbp), %xmm2
movdqu (%rbp,%rdi), %xmm3
pcmpeqb %xmm2, %xmm3
movdqa %xmm7, %xmm2
pand %xmm3, %xmm2
pandn %xmm8, %xmm3
por %xmm2, %xmm3
movdqu %xmm3, (%r13,%rdx)
addq $0x10, %rdx
addq $0x10, %rbp
jmp 0x1a1177
movl %r11d, %edx
shrl $0x4, %edx
movl %r8d, %ebp
shrl $0x4, %ebp
movl %r8d, %edi
andl $-0x10, %edi
addq 0x10(%rsp), %rdi
movq %rcx, %rbx
cmpq %rdx, %rbp
ja 0x1a122d
movdqa (%rdi,%r14), %xmm2
paddb %xmm6, %xmm2
movdqa (%rdi,%r12), %xmm3
movdqa %xmm3, %xmm4
psrldq $0xf, %xmm4             # xmm4 = xmm4[15],zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero
pslldq $0x1, %xmm3             # xmm3 = zero,xmm3[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
por %xmm1, %xmm3
movdqa (%rdi), %xmm1
movdqa %xmm2, %xmm5
pcmpgtb %xmm0, %xmm5
pand %xmm2, %xmm5
movdqa %xmm3, %xmm2
pmaxub %xmm1, %xmm2
pmaxub %xmm5, %xmm2
movdqa %xmm2, %xmm5
psubb %xmm3, %xmm5
movdqa %xmm5, (%rdi)
psubb %xmm1, %xmm2
movdqa %xmm2, (%rdi,%r12)
incq %rbp
addq $0x10, %rdi
movdqa %xmm4, %xmm1
jmp 0x1a11c7
testq %r9, %r9
je 0x1a126c
cmpl %r11d, %r10d
jg 0x1a127d
cmpl %r8d, %r10d
jl 0x1a127d
movl %r10d, %edx
cmpl %r11d, %r10d
jge 0x1a128f
leaq 0x1(%rdx), %rdi
movq 0x20(%rsp), %rcx
movzbl (%rcx,%rdx), %r8d
movq 0x10(%rsp), %rcx
movzbl 0x1(%rcx,%rdx), %edx
cmpb %dl, %r8b
cmoval %r10d, %edi
cmoval %r8d, %edx
movl %edi, %r10d
jmp 0x1a1297
movq 0x20(%rsp), %rcx
movzbl (%rcx), %edx
subl 0x70(%rsp), %edx
xorl %r10d, %r10d
jmp 0x1a12da
movslq %r10d, %r10
movq 0x10(%rsp), %rcx
movb 0x1(%rcx,%r10), %dl
incq %r10
jmp 0x1a1297
movq 0x20(%rsp), %rcx
movb (%rcx,%rdx), %dl
movl 0xc(%rsp), %r8d
movzbl %dl, %edx
subl 0x80(%rsp), %edx
addl %r15d, %edx
movl (%rbx), %ecx
movl %ecx, %edi
andl $0x7fffffff, %edi       # imm = 0x7FFFFFFF
subl %edx, %edi
jge 0x1a12d0
andl $0x80000000, %ecx       # imm = 0x80000000
orl %edx, %ecx
movl %ecx, (%rbx)
movl %r10d, 0x8(%rbx)
movl %r9d, %ecx
subl %r10d, %ecx
movl %ecx, 0x4(%rbx)
jmp 0x1a12da
testl %r8d, %r8d
js 0x1a12da
cmpl %r8d, %edi
jg 0x1a12f9
incq %r9
movq 0x18(%rsp), %rcx
decl %ecx
movq %rcx, 0x18(%rsp)
movl %edx, %r15d
jmp 0x1a10b9
movq 0x28(%rsp), %r9
movl %r15d, %edx
cmpl 0x60(%rsp), %r9d
jne 0x1a1305
movl %edx, 0x1c(%rbx)
jmp 0x1a1309
orb $-0x80, 0x3(%rbx)
movq 0x58(%rsp), %rdi
movq 0x50(%rsp), %rsi
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x19e38c
nopl (%rax)