// File: /workspace/github_c_makefile_star2_O1/lh3[P]minimap2/ksw2_ll_sse.c
// Function: ksw_ll_i16
int ksw_ll_i16(void *q_, int tlen, const uint8_t *target, int _gapo, int _gape, int *qe, int *te)
{
	kswq_t *q = (kswq_t*)q_;
	int slen, i, gmax = 0, qlen8;
	__m128i zero, gapoe, gape, *H0, *H1, *E, *Hmax;
	uint16_t *H8;

#define __max_8(ret, xx) do { \
		(xx) = _mm_max_epi16((xx), _mm_srli_si128((xx), 8)); \
		(xx) = _mm_max_epi16((xx), _mm_srli_si128((xx), 4)); \
		(xx) = _mm_max_epi16((xx), _mm_srli_si128((xx), 2)); \
		(ret) = _mm_extract_epi16((xx), 0); \
	} while (0)

	// initialization
	*qe = *te = -1;
	zero = _mm_set1_epi32(0);
	gapoe = _mm_set1_epi16(_gapo + _gape);
	gape = _mm_set1_epi16(_gape);
	H0 = q->H0; H1 = q->H1; E = q->E; Hmax = q->Hmax;
	slen = q->slen, qlen8 = slen * 8;
	memset(E,    0, slen * sizeof(__m128i));
	memset(H0,   0, slen * sizeof(__m128i));
	memset(Hmax, 0, slen * sizeof(__m128i));
	// the core loop
	for (i = 0; i < tlen; ++i) {
		int j, k, imax;
		__m128i e, h, f = zero, max = zero, *S = q->qp + target[i] * slen; // s is the 1st score vector
		h = _mm_load_si128(H0 + slen - 1); // h={2,5,8,11,14,17,-1,-1} in the above example
		h = _mm_slli_si128(h, 2);
		for (j = 0; LIKELY(j < slen); ++j) {
			h = _mm_adds_epi16(h, *S++);
			e = _mm_load_si128(E + j);
			h = _mm_max_epi16(h, e);
			h = _mm_max_epi16(h, f);
			max = _mm_max_epi16(max, h);
			_mm_store_si128(H1 + j, h);
			h = _mm_subs_epu16(h, gapoe);
			e = _mm_subs_epu16(e, gape);
			e = _mm_max_epi16(e, h);
			_mm_store_si128(E + j, e);
			f = _mm_subs_epu16(f, gape);
			f = _mm_max_epi16(f, h);
			h = _mm_load_si128(H0 + j);
		}
		for (k = 0; LIKELY(k < 8); ++k) {
			f = _mm_slli_si128(f, 2);
			for (j = 0; LIKELY(j < slen); ++j) {
				h = _mm_load_si128(H1 + j);
				h = _mm_max_epi16(h, f);
				_mm_store_si128(H1 + j, h);
				h = _mm_subs_epu16(h, gapoe);
				f = _mm_subs_epu16(f, gape);
				if(UNLIKELY(!_mm_movemask_epi8(_mm_cmpgt_epi16(f, h)))) goto end_loop_i16;
			}
		}
end_loop_i16:
		__max_8(imax, max);
		if (imax >= gmax) {
			gmax = imax; *te = i;
			memcpy(Hmax, H1, slen * sizeof(__m128i));
		}
		S = H1; H1 = H0; H0 = S;
	}
	for (i = 0, H8 = (uint16_t*)Hmax; i < qlen8; ++i)
		if ((int)H8[i] == gmax) *qe = i / 8 + i % 8 * slen;
	return gmax;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x58, %rsp
movl %r8d, 0x10(%rsp)
movl %ecx, 0x20(%rsp)
movq %rdx, 0x50(%rsp)
movl %esi, (%rsp)
movq 0x90(%rsp), %rcx
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movl %eax, (%rcx)
movq %r9, 0x30(%rsp)
movl %eax, (%r9)
movq 0x18(%rdi), %r15
movq 0x20(%rdi), %rbx
movq 0x28(%rdi), %r13
movq 0x30(%rdi), %r14
movq %rdi, 0x48(%rsp)
movslq 0x4(%rdi), %r12
movq %r12, %rbp
shlq $0x4, %rbp
movq %r13, %rdi
xorl %esi, %esi
movq %rbp, %rdx
callq 0x21b0
movq %r15, %rdi
xorl %esi, %esi
movq %rbp, %rdx
callq 0x21b0
movq %r14, 0x8(%rsp)
movq %r14, %rdi
xorl %esi, %esi
movq %rbp, %rdx
callq 0x21b0
movl (%rsp), %ecx
xorl %eax, %eax
movq %r12, %r9
testl %ecx, %ecx
jle 0x1ed9f
movq %rbp, %rdx
movl 0x10(%rsp), %eax
movl 0x20(%rsp), %esi
addl %eax, %esi
movd %esi, %xmm0
pshuflw $0x0, %xmm0, %xmm0      # xmm0 = xmm0[0,0,0,0,4,5,6,7]
pshufd $0x0, %xmm0, %xmm5      # xmm5 = xmm0[0,0,0,0]
movd %eax, %xmm0
pshuflw $0x0, %xmm0, %xmm0      # xmm0 = xmm0[0,0,0,0,4,5,6,7]
pshufd $0x0, %xmm0, %xmm6      # xmm6 = xmm0[0,0,0,0]
movl %ecx, %r8d
movl %r9d, %r14d
shlq $0x4, %r14
xorl %ebp, %ebp
xorl %eax, %eax
movq %r9, 0x40(%rsp)
movq %rdx, 0x38(%rsp)
movdqa %xmm5, 0x20(%rsp)
movdqa %xmm6, 0x10(%rsp)
movq %r8, (%rsp)
movq %r15, %r12
testl %r9d, %r9d
jle 0x1ed92
movdqa -0x10(%r12,%rdx), %xmm2
movq 0x50(%rsp), %rcx
movzbl (%rcx,%rbp), %esi
imull %r9d, %esi
shlq $0x4, %rsi
movq 0x48(%rsp), %rcx
addq 0x10(%rcx), %rsi
pslldq $0x2, %xmm2             # xmm2 = zero,zero,xmm2[0,1,2,3,4,5,6,7,8,9,10,11,12,13]
pxor %xmm0, %xmm0
xorl %ecx, %ecx
pxor %xmm1, %xmm1
paddsw (%rsi,%rcx), %xmm2
movdqa (%r13,%rcx), %xmm3
movdqa %xmm3, %xmm4
pmaxsw %xmm1, %xmm4
pmaxsw %xmm2, %xmm4
pmaxsw %xmm4, %xmm0
movdqa %xmm4, (%rbx,%rcx)
psubusw %xmm5, %xmm4
psubusw %xmm6, %xmm3
pmaxsw %xmm4, %xmm3
movdqa %xmm3, (%r13,%rcx)
psubusw %xmm6, %xmm1
pmaxsw %xmm4, %xmm1
movdqa (%r12,%rcx), %xmm2
addq $0x10, %rcx
cmpq %rcx, %r14
jne 0x1ec89
xorl %esi, %esi
pslldq $0x2, %xmm1             # xmm1 = zero,zero,xmm1[0,1,2,3,4,5,6,7,8,9,10,11,12,13]
testl %r9d, %r9d
jle 0x1ed11
xorl %ecx, %ecx
movdqa (%rbx,%rcx), %xmm2
pmaxsw %xmm1, %xmm2
movdqa %xmm2, (%rbx,%rcx)
psubusw %xmm5, %xmm2
psubusw %xmm6, %xmm1
movdqa %xmm1, %xmm3
pcmpgtw %xmm2, %xmm3
pmovmskb %xmm3, %edi
testl %edi, %edi
je 0x1ed18
addq $0x10, %rcx
cmpq %rcx, %r14
jne 0x1ece2
incl %esi
cmpl $0x8, %esi
jne 0x1ecd6
movdqa %xmm0, %xmm1
psrldq $0x8, %xmm1             # xmm1 = xmm1[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero
pmaxsw %xmm0, %xmm1
movdqa %xmm1, %xmm0
psrldq $0x4, %xmm0             # xmm0 = xmm0[4,5,6,7,8,9,10,11,12,13,14,15],zero,zero,zero,zero
pmaxsw %xmm1, %xmm0
movdqa %xmm0, %xmm1
psrldq $0x2, %xmm1             # xmm1 = xmm1[2,3,4,5,6,7,8,9,10,11,12,13,14,15],zero,zero
pmaxsw %xmm0, %xmm1
pextrw $0x0, %xmm1, %r15d
cmpl %r15d, %eax
ja 0x1ed7e
movq 0x90(%rsp), %rax
movl %ebp, (%rax)
movq 0x8(%rsp), %rdi
movq %rbx, %rsi
callq 0x22a0
movq (%rsp), %r8
movdqa 0x10(%rsp), %xmm6
movdqa 0x20(%rsp), %xmm5
movq 0x38(%rsp), %rdx
movq 0x40(%rsp), %r9
movl %r15d, %eax
incq %rbp
movq %rbx, %r15
movq %r12, %rbx
cmpq %r8, %rbp
jne 0x1ec4d
jmp 0x1ed9f
pxor %xmm1, %xmm1
pxor %xmm0, %xmm0
jmp 0x1ecd4
testl %r9d, %r9d
movq 0x30(%rsp), %rdi
movq 0x8(%rsp), %r8
jle 0x1ede8
leal (,%r9,8), %ecx
cmpl $0x2, %ecx
movl $0x1, %r10d
cmovgel %ecx, %r10d
xorl %ecx, %ecx
movzwl (%r8,%rcx,2), %edx
cmpl %edx, %eax
jne 0x1ede0
movl %ecx, %edx
shrl $0x3, %edx
movl %ecx, %esi
andl $0x7, %esi
imull %r9d, %esi
addl %edx, %esi
movl %esi, (%rdi)
incq %rcx
cmpq %rcx, %r10
jne 0x1edc5
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop