// File: /workspace/github_c_makefile_star2_O3/nh13[P]ksw/src/parasail/contrib/ssw/ssw.c
// Function: sw_sse2_byte
static alignment_end* sw_sse2_byte (const int8_t* ref,
							 int8_t ref_dir,	/* 0: forward ref; 1: reverse ref*/
							 int32_t refLen,
							 int32_t readLen,
							 const uint8_t weight_gapO, /* will be used as - */
							 const uint8_t weight_gapE, /* will be used as - */
							 const __m128i* vProfile,
							 uint8_t terminate,	/* the best alignment score: used to terminate
												   the matrix calculation when locating the
												   alignment beginning point. If this score
												   is set to 0, it will not be used */
	 						 uint8_t bias,  /* Shift 0 point to a positive value. */
							 int32_t maskLen) {

/* Put the largest number of the 16 numbers in vm into m.*/
#define max16(m, vm) (vm) = _mm_max_epu8((vm), _mm_srli_si128((vm), 8)); \
					  (vm) = _mm_max_epu8((vm), _mm_srli_si128((vm), 4)); \
					  (vm) = _mm_max_epu8((vm), _mm_srli_si128((vm), 2)); \
					  (vm) = _mm_max_epu8((vm), _mm_srli_si128((vm), 1)); \
					  (m) = _mm_extract_epi16((vm), 0)

	uint8_t max = 0;		                     /* the max alignment score */
	int32_t end_read = readLen - 1;
	int32_t end_ref = -1; /* 0_based best alignment ending point; Initialized as isn't aligned -1. */
	int32_t segLen = (readLen + 15) / 16; /* number of segment */

	/* array to record the largest score of each reference position */
	uint8_t* maxColumn = (uint8_t*) calloc(refLen, 1);

	/* array to record the alignment read ending position of the largest score of each reference position */
	int32_t* end_read_column = (int32_t*) calloc(refLen, sizeof(int32_t));

	/* Define 16 byte 0 vector. */
	__m128i vZero = _mm_set1_epi32(0);

	__m128i* pvHStore = (__m128i*) calloc(segLen, sizeof(__m128i));
	__m128i* pvHLoad = (__m128i*) calloc(segLen, sizeof(__m128i));
	__m128i* pvE = (__m128i*) calloc(segLen, sizeof(__m128i));
	__m128i* pvHmax = (__m128i*) calloc(segLen, sizeof(__m128i));

	int32_t i, j;
	/* 16 byte insertion begin vector */
	__m128i vGapO = _mm_set1_epi8(weight_gapO);

	/* 16 byte insertion extension vector */
	__m128i vGapE = _mm_set1_epi8(weight_gapE);

	/* 16 byte bias vector */
	__m128i vBias = _mm_set1_epi8(bias);

	__m128i vMaxScore = vZero; /* Trace the highest score of the whole SW matrix. */
	__m128i vMaxMark = vZero; /* Trace the highest score till the previous column. */
	__m128i vTemp;
	int32_t edge, begin = 0, end = refLen, step = 1;
	uint8_t *t;
	int32_t column_len;
    alignment_end* bests;

	/* outer loop to process the reference sequence */
	if (ref_dir == 1) {
		begin = refLen - 1;
		end = -1;
		step = -1;
	}
	for (i = begin; LIKELY(i != end); i += step) {
		const __m128i* vP;
		__m128i* pv;
		int32_t cmp;
		__m128i e, vF = vZero, vMaxColumn = vZero; /* Initialize F value to 0.
							   Any errors to vH values will be corrected in the Lazy_F loop.
							 */

		__m128i vH = pvHStore[segLen - 1];
		vH = _mm_slli_si128 (vH, 1); /* Shift the 128-bit value in vH left by 1 byte. */
		vP = vProfile + ref[i] * segLen; /* Right part of the vProfile */

		/* Swap the 2 H buffers. */
		pv = pvHLoad;
		pvHLoad = pvHStore;
		pvHStore = pv;

		/* inner loop to process the query sequence */
		for (j = 0; LIKELY(j < segLen); ++j) {
			vH = _mm_adds_epu8(vH, _mm_load_si128(vP + j));
			vH = _mm_subs_epu8(vH, vBias); /* vH will be always > 0 */

			/* Get max from vH, vE and vF. */
			e = _mm_load_si128(pvE + j);
			vH = _mm_max_epu8(vH, e);
			vH = _mm_max_epu8(vH, vF);
			vMaxColumn = _mm_max_epu8(vMaxColumn, vH);

			/* Save vH values. */
			_mm_store_si128(pvHStore + j, vH);

			/* Update vE value. */
			vH = _mm_subs_epu8(vH, vGapO); /* saturation arithmetic, result >= 0 */
			e = _mm_subs_epu8(e, vGapE);
			e = _mm_max_epu8(e, vH);
			_mm_store_si128(pvE + j, e);

			/* Update vF value. */
			vF = _mm_subs_epu8(vF, vGapE);
			vF = _mm_max_epu8(vF, vH);

			/* Load the next vH. */
			vH = _mm_load_si128(pvHLoad + j);
		}

		/* Lazy_F loop: has been revised to disallow adjecent insertion and then deletion, so don't update E(i, j), learn from SWPS3 */
        /* reset pointers to the start of the saved data */
        j = 0;
        vH = _mm_load_si128 (pvHStore + j);

        /*  the computed vF value is for the given column.  since */
        /*  we are at the end, we need to shift the vF value over */
        /*  to the next column. */
        vF = _mm_slli_si128 (vF, 1);
        vTemp = _mm_subs_epu8 (vH, vGapO);
		vTemp = _mm_subs_epu8 (vF, vTemp);
		vTemp = _mm_cmpeq_epi8 (vTemp, vZero);
		cmp  = _mm_movemask_epi8 (vTemp);

        while (cmp != 0xffff)
        {
            vH = _mm_max_epu8 (vH, vF);
			vMaxColumn = _mm_max_epu8(vMaxColumn, vH);
            _mm_store_si128 (pvHStore + j, vH);
            vF = _mm_subs_epu8 (vF, vGapE);
            j++;
            if (j >= segLen)
            {
                j = 0;
                vF = _mm_slli_si128 (vF, 1);
            }
            vH = _mm_load_si128 (pvHStore + j);

            vTemp = _mm_subs_epu8 (vH, vGapO);
            vTemp = _mm_subs_epu8 (vF, vTemp);
            vTemp = _mm_cmpeq_epi8 (vTemp, vZero);
            cmp  = _mm_movemask_epi8 (vTemp);
        }

		vMaxScore = _mm_max_epu8(vMaxScore, vMaxColumn);
		vTemp = _mm_cmpeq_epi8(vMaxMark, vMaxScore);
		cmp = _mm_movemask_epi8(vTemp);
		if (cmp != 0xffff) {
			uint8_t temp;
			vMaxMark = vMaxScore;
			max16(temp, vMaxScore);
			vMaxScore = vMaxMark;

			if (LIKELY(temp > max)) {
				max = temp;
				if (max + bias >= 255) break;	/*overflow*/
				end_ref = i;

				/* Store the column with the highest alignment score in order to trace the alignment ending position on read. */
				for (j = 0; LIKELY(j < segLen); ++j) pvHmax[j] = pvHStore[j];
			}
		}

		/* Record the max score of current column. */
		max16(maxColumn[i], vMaxColumn);
		if (maxColumn[i] == terminate) break;
	}

	/* Trace the alignment ending position on read. */
	t = (uint8_t*)pvHmax;
	column_len = segLen * 16;
	for (i = 0; LIKELY(i < column_len); ++i, ++t) {
		int32_t temp;
		if (*t == max) {
			temp = i / 16 + i % 16 * segLen;
			if (temp < end_read) end_read = temp;
		}
	}

	free(pvHmax);
	free(pvE);
	free(pvHLoad);
	free(pvHStore);

	/* Find the most possible 2nd best alignment. */
	bests = (alignment_end*) calloc(2, sizeof(alignment_end));
	bests[0].score = max + bias >= 255 ? 255 : max;
	bests[0].ref = end_ref;
	bests[0].read = end_read;

	bests[1].score = 0;
	bests[1].ref = 0;
	bests[1].read = 0;

	edge = (end_ref - maskLen) > 0 ? (end_ref - maskLen) : 0;
	for (i = 0; i < edge; i ++) {
		if (maxColumn[i] > bests[1].score) {
			bests[1].score = maxColumn[i];
			bests[1].ref = i;
		}
	}
	edge = (end_ref + maskLen) > refLen ? refLen : (end_ref + maskLen);
	for (i = edge + 1; i < refLen; i ++) {
		if (maxColumn[i] > bests[1].score) {
			bests[1].score = maxColumn[i];
			bests[1].ref = i;
		}
	}

	free(maxColumn);
	free(end_read_column);
	return bests;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movl %r9d, 0x2c(%rsp)
movl %r8d, 0x28(%rsp)
movl %edx, %r8d
movl %edx, 0x10(%rsp)
movl %esi, 0xc(%rsp)
movq %rdi, 0x30(%rsp)
movq %rcx, 0x20(%rsp)
leal 0xf(%rcx), %eax
pushq $0x10
popq %rcx
cltd
idivl %ecx
movl %eax, %r15d
movslq %r8d, %rbx
pushq $0x1
popq %rsi
movq %rbx, %rdi
callq 0x29b0e0
movq %rax, 0x18(%rsp)
movslq %r15d, %r14
pushq $0x10
popq %rbp
movq %r14, %rdi
movq %rbp, %rsi
callq 0x29b0e0
movq %rax, %r12
movq %r14, %rdi
movq %rbp, %rsi
callq 0x29b0e0
movq %rax, %r13
movq %r14, %rdi
movq %rbp, %rsi
callq 0x29b0e0
movq %rax, %rbp
movq %r14, %rdi
pushq $0x10
popq %rsi
callq 0x29b0e0
movl 0x80(%rsp), %r9d
movl 0xc(%rsp), %r8d
decl %ebx
xorl %edx, %edx
cmpb $0x1, %r8b
cmovnel %edx, %ebx
pushq $-0x1
popq %rdi
movl 0x10(%rsp), %esi
cmovel %edi, %esi
movzbl %r9b, %ecx
movl %ecx, 0x14(%rsp)
pushq $0x1
popq %rcx
cmpl %esi, %ebx
je 0x29ba15
movd 0x28(%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]
movd 0x2c(%rsp), %xmm1
punpcklbw %xmm1, %xmm1    # xmm1 = xmm1[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
pshuflw $0x0, %xmm1, %xmm1      # xmm1 = xmm1[0,0,0,0,4,5,6,7]
pshufd $0x0, %xmm1, %xmm1      # xmm1 = xmm1[0,0,0,0]
movd %r9d, %xmm2
punpcklbw %xmm2, %xmm2    # xmm2 = xmm2[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
pshuflw $0x0, %xmm2, %xmm2      # xmm2 = xmm2[0,0,0,0,4,5,6,7]
pshufd $0x0, %xmm2, %xmm2      # xmm2 = xmm2[0,0,0,0]
xorl %edi, %edi
cmpb $0x1, %r8b
setne %dil
leal -0x1(%r15), %r8d
movslq %r8d, %r9
cmpl $0x2, %r15d
movl %ecx, %r10d
cmovgel %r15d, %r10d
movslq %ebx, %r11
leaq -0x1(,%rdi,2), %rdi
shlq $0x4, %r10
pxor %xmm4, %xmm4
pushq $-0x1
popq %r8
movl %r8d, 0xc(%rsp)
shlq $0x4, %r9
xorl %ebx, %ebx
movq %r12, %r8
pxor %xmm3, %xmm3
movq %r13, %r12
movq %r8, %r13
pxor %xmm6, %xmm6
pxor %xmm5, %xmm5
cmpl $0x0, 0x20(%rsp)
jle 0x29b758
movq 0x30(%rsp), %r8
movsbl (%r8,%r11), %r8d
imull %r15d, %r8d
movslq %r8d, %r14
shlq $0x4, %r14
addq 0x70(%rsp), %r14
movdqa (%r13,%r9), %xmm7
pslldq $0x1, %xmm7             # xmm7 = zero,xmm7[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
xorl %r8d, %r8d
paddusb (%r14,%r8), %xmm7
psubusb %xmm2, %xmm7
movdqa (%rbp,%r8), %xmm8
movdqa %xmm8, %xmm9
pmaxub %xmm6, %xmm9
pmaxub %xmm7, %xmm9
pmaxub %xmm9, %xmm5
movdqa %xmm9, (%r12,%r8)
psubusb %xmm0, %xmm9
psubusb %xmm1, %xmm8
pmaxub %xmm9, %xmm8
movdqa %xmm8, (%rbp,%r8)
psubusb %xmm1, %xmm6
pmaxub %xmm9, %xmm6
movdqa (%r13,%r8), %xmm7
addq $0x10, %r8
cmpq %r8, %r10
jne 0x29b6fe
movdqa (%r12), %xmm7
pslldq $0x1, %xmm6             # xmm6 = zero,xmm6[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
movdqa %xmm7, %xmm8
psubusb %xmm0, %xmm8
pminub %xmm6, %xmm8
pcmpeqb %xmm6, %xmm8
pmovmskb %xmm8, %r8d
cmpl $0xffff, %r8d           # imm = 0xFFFF
je 0x29b7e4
xorl %r14d, %r14d
pmaxub %xmm6, %xmm7
movslq %r14d, %r14
movq %r14, %r8
shlq $0x4, %r8
movdqa %xmm7, (%r12,%r8)
psubusb %xmm1, %xmm6
incl %r14d
cmpl %r15d, %r14d
cmovgel %edx, %r14d
jl 0x29b7b1
pslldq $0x1, %xmm6             # xmm6 = zero,xmm6[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
pmaxub %xmm7, %xmm5
movslq %r14d, %r8
shlq $0x4, %r8
movdqa (%r12,%r8), %xmm7
movdqa %xmm7, %xmm8
psubusb %xmm0, %xmm8
pminub %xmm6, %xmm8
pcmpeqb %xmm6, %xmm8
pmovmskb %xmm8, %r8d
cmpl $0xffff, %r8d           # imm = 0xFFFF
jne 0x29b788
pmaxub %xmm5, %xmm3
movdqa %xmm4, %xmm6
pcmpeqb %xmm3, %xmm6
pmovmskb %xmm6, %r8d
xorl $0xffff, %r8d           # imm = 0xFFFF
je 0x29b87d
movdqa %xmm3, %xmm4
psrldq $0x8, %xmm4             # xmm4 = xmm4[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero
pmaxub %xmm3, %xmm4
movdqa %xmm4, %xmm6
psrldq $0x4, %xmm6             # xmm6 = xmm6[4,5,6,7,8,9,10,11,12,13,14,15],zero,zero,zero,zero
pmaxub %xmm4, %xmm6
movdqa %xmm6, %xmm4
psrldq $0x2, %xmm4             # xmm4 = xmm4[2,3,4,5,6,7,8,9,10,11,12,13,14,15],zero,zero
pmaxub %xmm6, %xmm4
movdqa %xmm4, %xmm6
psrldq $0x1, %xmm6             # xmm6 = xmm6[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],zero
pmaxub %xmm4, %xmm6
movd %xmm6, %r8d
cmpb %bl, %r8b
jbe 0x29b8d7
movzbl %r8b, %ebx
addl 0x14(%rsp), %ebx
cmpl $0xfe, %ebx
ja 0x29b8dd
cmpl $0x0, 0x20(%rsp)
jle 0x29b871
xorl %ebx, %ebx
movdqa (%r12,%rbx), %xmm4
movdqa %xmm4, (%rax,%rbx)
addq $0x10, %rbx
cmpq %rbx, %r10
jne 0x29b85d
movdqa %xmm3, %xmm4
movl %r11d, 0xc(%rsp)
movl %r8d, %ebx
movdqa %xmm5, %xmm6
psrldq $0x8, %xmm6             # xmm6 = xmm6[8,9,10,11,12,13,14,15],zero,zero,zero,zero,zero,zero,zero,zero
pmaxub %xmm5, %xmm6
movdqa %xmm6, %xmm5
psrldq $0x4, %xmm5             # xmm5 = xmm5[4,5,6,7,8,9,10,11,12,13,14,15],zero,zero,zero,zero
pmaxub %xmm6, %xmm5
movdqa %xmm5, %xmm6
psrldq $0x2, %xmm6             # xmm6 = xmm6[2,3,4,5,6,7,8,9,10,11,12,13,14,15],zero,zero
pmaxub %xmm5, %xmm6
movdqa %xmm6, %xmm5
psrldq $0x1, %xmm5             # xmm5 = xmm5[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],zero
pmaxub %xmm6, %xmm5
movd %xmm5, %r8d
movq 0x18(%rsp), %r14
movb %r8b, (%r14,%r11)
cmpb 0x78(%rsp), %r8b
je 0x29b8e0
addq %rdi, %r11
movq %r12, %r8
cmpl %r11d, %esi
jne 0x29b6bc
jmp 0x29b8e0
movdqa %xmm3, %xmm4
jmp 0x29b87d
movl %r8d, %ebx
movq 0x20(%rsp), %rdx
leal -0x1(%rdx), %r14d
testl %edx, %edx
jle 0x29b91e
movl %r15d, %edx
shll $0x4, %edx
cmpl $0x2, %edx
cmovgel %edx, %ecx
xorl %edx, %edx
cmpb %bl, (%rax,%rdx)
jne 0x29b917
movl %edx, %esi
shrl $0x4, %esi
movl %edx, %edi
andl $0xf, %edi
imull %r15d, %edi
addl %esi, %edi
cmpl %r14d, %edi
cmovll %edi, %r14d
incq %rdx
cmpl %edx, %ecx
jne 0x29b8fb
movq %rax, %rdi
callq 0x29b170
movq %rbp, %rdi
callq 0x29b170
movq %r13, %rdi
callq 0x29b170
movq %r12, %rdi
callq 0x29b170
pushq $0x2
popq %rdi
pushq $0xc
popq %rsi
callq 0x29b0e0
movq %rax, %r15
movzbl %bl, %eax
movl 0x14(%rsp), %edx
addl %eax, %edx
movl $0xff, %ecx
cmpl %ecx, %edx
cmovbl %eax, %ecx
movw %cx, (%r15)
movl 0xc(%rsp), %r9d
movl %r9d, 0x4(%r15)
movl %r14d, 0x8(%r15)
andw $0x0, 0xc(%r15)
andq $0x0, 0x10(%r15)
movl %r9d, %eax
movl 0x88(%rsp), %r10d
subl %r10d, %eax
jle 0x29b9b9
movl %eax, %ecx
xorl %edx, %edx
xorl %eax, %eax
movl 0x10(%rsp), %r8d
movq 0x18(%rsp), %rdi
movzbl (%rdi,%rdx), %esi
cmpw %si, %ax
jae 0x29b9aa
movl %edx, 0x10(%r15)
movl %esi, %eax
incq %rdx
cmpq %rdx, %rcx
jne 0x29b99b
movw %ax, 0xc(%r15)
jmp 0x29b9c5
xorl %eax, %eax
movl 0x10(%rsp), %r8d
movq 0x18(%rsp), %rdi
addl %r10d, %r9d
cmpl %r8d, %r9d
cmovgel %r8d, %r9d
incl %r9d
cmpl %r8d, %r9d
jge 0x29b9fe
movslq %r9d, %rdx
movq %rdi, %rcx
addq %rdx, %rcx
movzbl (%rcx), %edx
cmpw %dx, %ax
jae 0x29b9ee
movl %r9d, 0x10(%r15)
movl %edx, %eax
incq %rcx
incl %r9d
cmpl %r9d, %r8d
jne 0x29b9e0
movw %ax, 0xc(%r15)
callq 0x29b170
movq %r15, %rax
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl %edi, 0xc(%rsp)
xorl %ebx, %ebx
jmp 0x29b8e0