// File: /workspace/github_c_makefile_star2_O3/c-zhou[P]oatk/syncmer.c
// Function: process_kmer_cluster
static void process_kmer_cluster(uint128_t *scm, uint32_t n, syncmer_db_t *scm_db, sr_db_t *sr_db)
{
    int n_clus, *clus;
    MYMALLOC(clus, n);

    if (n == 1) {
        // no hash collision for sure
        n_clus = 1;
        clus[0] = 0;
    } else {
        int i, j, k, b, c, B, C, p0, p1, rev, res;
        uint8_t *kmer, *kmer_list;
        uint32_t n_s;
        uint64_t sid;
        size_t s;

        k = sr_db->k;
        B = (((k - 1) >> 3) + 1) << 3; // maxmum number bytes to hold syncmer 64bit aligned
        C = B >> 3; // number of comparsions of 64bit interger
        n_clus = 0;
        kmer_list = 0;
        MYMALLOC(kmer, B);

        for (s = 0; s < n; ++s) {
            sid = (uint64_t) scm[s] >> 32;
            n_s = (uint32_t) ((uint64_t) scm[s]) >> 1;
            rev = scm[s] & 1;
            p0 = sr_db->a[sid].m_pos[n_s] >> 1;
            p1 = p0 + k - 1;
            res = rev? ((p1&3)^3)<<1 : (p0&3)<<1;
            b = p1 / 4 - p0 / 4 + 1; // actual number bytes holding syncmer
            memcpy(kmer, sr_db->a[sid].hoco_s + p0 / 4, b);
            // do reverse complementary
            if (rev) {
                for (i = 0, j = b - 1; i < j; ++i, --j) {
                    c = kmer[i];
                    kmer[i] = comp_seq8_table[kmer[j]];
                    kmer[j] = comp_seq8_table[c];
                }
                if (i == j) kmer[i] = comp_seq8_table[kmer[i]];
            }
            // do bit shift to align syncmer bytes
            for (i = 0; i < b - 1; ++i) {
                kmer[i] <<= res;
                kmer[i] |= kmer[i+1] >> (8-res);
            }
            kmer[b-1] <<= res;
            // real bytes
            b = (k - 1) / 4 + 1;
            // mask the lower bits
            kmer[b-1] &= lmask[k&3];
            // mask the remaining bytes
            MYBZERO(&kmer[b], B - b);
            // compare to the existing kmers to find hash collision
            for (i = 0; i < n_clus; ++i)
                if (equal_array(kmer, &kmer_list[i * B], C))
                    break;
            clus[s] = i;
            if (i >= n_clus) {
                // new kmer
                // add to kmer list
                ++n_clus;
                MYREALLOC(kmer_list, n_clus * B);
                memcpy(&kmer_list[(n_clus - 1) * B], kmer, B);
            }
        }
#ifdef DEBUG_CHECK_HASH_COLLISION
        uint64_t h64 = (uint64_t) (scm[0] >> 64);
        for (i = 0; i < n_clus; ++i)
            assert(h64 == MurmurHash64A(&kmer_list[i * B], (k - 1) / 4 + 1, murmur3_seed));
#endif
        free(kmer);
        free(kmer_list);
    }

    // add each cluster to syncmer database
    uint32_t s, *cnts;
    MYCALLOC(cnts, n_clus);
    for (s = 0; s < n; ++s)
        ++cnts[clus[s]];

    syncmer_t *syncmer;
    int i;
    for (i = 0; i < n_clus; ++i) {
        kv_pushp(syncmer_t, *scm_db, &syncmer);
        syncmer->h = (uint64_t) (scm[0] >> 64);
        syncmer->s = UINT64_MAX; // UINT64_MAX cannot be a smer as the first bit of smer is always zero
        syncmer->cov = 0;
        syncmer->del = 0;
        MYMALLOC(syncmer->m_pos, cnts[i]);
    }

    uint64_t smer;
    for (s = 0; s < n; ++s) {
        // update syncmer database
        syncmer = &scm_db->a[scm_db->n - n_clus + clus[s]];
        syncmer->m_pos[syncmer->cov++] = (uint64_t) scm[s];
        smer = sr_db->a[(uint64_t) scm[s] >> 32].s_mer[(uint32_t) ((uint64_t) scm[s]) >> 1];
        if (syncmer->s == UINT64_MAX) {
            syncmer->s = smer;
        } else if (syncmer->s != smer) {
            fprintf(stderr, "[E::%s] identical kmers have different smers\n", __func__);
            fprintf(stderr, "[E::%s] kmer hash  : %lu\n", __func__, syncmer->h);
            fprintf(stderr, "[E::%s] smer code 0: %lu; read id: %lu\n", __func__, syncmer->s, syncmer->m_pos[0] >> 32);
            fprintf(stderr, "[E::%s] smer code 1: %lu; read id: %lu\n", __func__, smer, (uint64_t) scm[s] >> 32);
            exit(EXIT_FAILURE);
        }
        // update read database
        sr_db->a[(uint64_t) scm[s] >> 32].k_mer[(uint32_t) ((uint64_t) scm[s]) >> 1] = (scm_db->n - n_clus + clus[s]) << 1;
    }

#ifdef DEBUG_CHECK_HASH_COLLISION
    if (n_clus > 1) {
        fprintf(stderr, "[DEBUG_CHECK_HASH_COLLISION::%s] hash collision: hash = %lu; clus = %d\n", 
                __func__, (uint64_t) (scm[0] >> 64), n_clus);
        for (i = 0; i < n_clus; ++i)
            fprintf(stderr, "[DEBUG_CHECK_HASH_COLLISION::%s] clus %d: read id %lu\n", 
                    __func__, i, scm_db->a[scm_db->n - n_clus + i].m_pos[0] >> 32);
    }
#endif    

    free(cnts);
    free(clus);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x78, %rsp
movq %rcx, %r12
movq %rdx, 0x18(%rsp)
movl %esi, %r13d
movq %rdi, %rbx
movl %esi, %r14d
leaq (,%r14,4), %rdi
callq 0x2310
cmpl $0x1, %r13d
movq %rbx, 0x30(%rsp)
movq %r12, 0x40(%rsp)
movq %r14, 0x38(%rsp)
movq %rax, 0x28(%rsp)
jne 0xfcd7
movl $0x0, (%rax)
movl $0x1, %r13d
movl $0x1, %edi
movl $0x4, %esi
callq 0x2250
movq 0x28(%rsp), %rdx
movq %rax, %rbp
movl $0x1, %esi
movq 0x18(%rsp), %r8
jmp 0xffef
movl 0x18(%r12), %eax
movq %rax, 0x8(%rsp)
leal -0x1(%rax), %r15d
movl %r15d, %ebx
andl $-0x8, %ebx
addl $0x8, %ebx
movslq %ebx, %rdi
movq %rdi, 0x50(%rsp)
callq 0x2310
movq %rax, %rbp
movl %r13d, 0x48(%rsp)
testl %r13d, %r13d
je 0xff9c
movl %ebx, %r13d
sarl $0x3, %r13d
leal 0x3(%r15), %eax
testl %r15d, %r15d
cmovnsl %r15d, %eax
sarl $0x2, %eax
movq 0x8(%rsp), %rdx
andl $0x3, %edx
leaq 0x109d0(%rip), %rcx     # 0x20700
movb (%rdx,%rcx), %cl
movb %cl, 0x7(%rsp)
movslq %eax, %rcx
leaq 0x1(%rcx,%rbp), %rax
movq %rax, 0x68(%rsp)
movq %rcx, %rax
movq %rcx, 0x70(%rsp)
notl %eax
addl %ebx, %eax
cltq
movq %rax, 0x60(%rsp)
movq $0x0, 0x8(%rsp)
xorl %eax, %eax
movq $0x0, 0x20(%rsp)
movq 0x30(%rsp), %r11
movq %r15, 0x58(%rsp)
movl %ebx, 0x4c(%rsp)
movq %rax, 0x10(%rsp)
shlq $0x4, %rax
movq (%r11,%rax), %rbx
movq %rbx, %rcx
shrq $0x20, %rcx
movl %ebx, %edx
shrl %edx
movq 0x10(%r12), %rax
imulq $0x58, %rcx, %rcx
movq 0x40(%rax,%rcx), %rsi
movl (%rsi,%rdx,4), %edx
movl %edx, %esi
shrl %esi
leal (%r15,%rsi), %edi
movl %edi, %r12d
notl %r12d
addl %r12d, %r12d
andl $0x6, %r12d
movl %edx, %r14d
andl $0x6, %r14d
addl %esi, %r15d
addl $0x3, %r15d
testl %edi, %edi
cmovnsl %edi, %r15d
sarl $0x2, %r15d
shrl $0x3, %edx
subl %edx, %r15d
leal 0x1(%r15), %edi
movq 0x18(%rax,%rcx), %rsi
addq %rdx, %rsi
movslq %edi, %rdx
movq %rbp, %rdi
callq 0x22b0
testb $0x1, %bl
cmovnel %r12d, %r14d
je 0xfe52
testl %r15d, %r15d
jle 0xfe34
movl %r15d, %eax
movq %rax, %rdx
xorl %ecx, %ecx
leaq 0x107f7(%rip), %r8      # 0x20600
movzbl (%rbp,%rcx), %esi
movzbl (%rbp,%rdx), %edi
movb (%rdi,%r8), %dil
movb %dil, (%rbp,%rcx)
movb (%rsi,%r8), %sil
movb %sil, (%rbp,%rdx)
incq %rcx
decq %rdx
cmpq %rdx, %rcx
jl 0xfe09
subl %ecx, %eax
jmp 0xfe39
xorl %ecx, %ecx
movl %r15d, %eax
cmpl %eax, %ecx
jne 0xfe52
movl %eax, %eax
movzbl (%rbp,%rax), %ecx
leaq 0x107b5(%rip), %rdx     # 0x20600
movb (%rcx,%rdx), %cl
movb %cl, (%rbp,%rax)
testl %r15d, %r15d
jle 0xfe83
movl %r15d, %eax
movb (%rbp), %cl
xorl %edx, %edx
movzbl %cl, %ebx
movzbl 0x1(%rbp,%rdx), %esi
shll $0x8, %ebx
orl %esi, %ebx
movl %r14d, %ecx
shll %cl, %ebx
movb %bh, (%rbp,%rdx)
leaq 0x1(%rdx), %rdi
movl %esi, %ecx
movq %rdi, %rdx
cmpq %rdi, %rax
jne 0xfe5f
movslq %r15d, %rax
movzbl (%rbp,%rax), %edx
movl %r14d, %ecx
shll %cl, %edx
movb %dl, (%rbp,%rax)
movb 0x7(%rsp), %al
movq 0x70(%rsp), %rcx
andb %al, (%rbp,%rcx)
xorl %ebx, %ebx
movq 0x68(%rsp), %rdi
xorl %esi, %esi
movq 0x60(%rsp), %rdx
callq 0x21e0
movq 0x8(%rsp), %r9
testl %r9d, %r9d
movq 0x30(%rsp), %r11
movq 0x40(%rsp), %r12
movq 0x38(%rsp), %r14
movq 0x28(%rsp), %r8
jle 0xff11
movl %r9d, %eax
movq 0x20(%rsp), %rdx
xorl %ecx, %ecx
movq 0x58(%rsp), %r15
testl %r13d, %r13d
jle 0xff8d
xorl %esi, %esi
movq (%rbp,%rsi,8), %rdi
cmpq (%rdx,%rsi,8), %rdi
jne 0xff01
incq %rsi
cmpq %rsi, %r13
jne 0xfeec
jmp 0xff71
incq %rcx
addq 0x50(%rsp), %rdx
cmpq %rax, %rcx
jne 0xfee1
movl %r9d, %ebx
movq 0x10(%rsp), %r12
movl %ebx, (%r8,%r12,4)
leal 0x1(%r9), %ebx
movl %ebx, %eax
movl 0x4c(%rsp), %r14d
imull %r14d, %eax
movslq %eax, %rsi
movq 0x20(%rsp), %rdi
movq %r9, %r15
callq 0x2350
imull %r14d, %r15d
movslq %r15d, %rdi
movq %rax, 0x20(%rsp)
addq %rax, %rdi
movq %rbp, %rsi
movq 0x50(%rsp), %rdx
callq 0x22b0
movq 0x30(%rsp), %r11
movq %r12, %rax
movq 0x40(%rsp), %r12
movl %ebx, %r9d
movq 0x38(%rsp), %r14
movq 0x58(%rsp), %r15
jmp 0xff7a
movq 0x10(%rsp), %rax
movl %ecx, (%r8,%rax,4)
movq %r9, 0x8(%rsp)
incq %rax
cmpq %r14, %rax
jne 0xfd79
jmp 0xffae
movq 0x10(%rsp), %rax
movl $0x0, (%r8,%rax,4)
jmp 0xff7a
movq $0x0, 0x20(%rsp)
movq $0x0, 0x8(%rsp)
movq %rbp, %rdi
callq 0x2060
movq 0x20(%rsp), %rdi
callq 0x2060
movslq 0x8(%rsp), %r13
movl $0x4, %esi
movq %r13, %rdi
callq 0x2250
movq %rax, %rbp
cmpl $0x0, 0x48(%rsp)
je 0x1018c
movq 0x18(%rsp), %r8
movq 0x28(%rsp), %rdx
movq 0x8(%rsp), %rsi
xorl %eax, %eax
movslq (%rdx,%rax,4), %rcx
incl (%rbp,%rcx,4)
incq %rax
cmpq %rax, %r14
jne 0xfff1
movl $0x0, 0x10(%rsp)
testl %esi, %esi
jle 0x100a1
movl %esi, %r15d
xorl %r12d, %r12d
movq (%r8), %rbx
movq 0x10(%r8), %r14
cmpq 0x8(%r8), %rbx
jne 0x10053
leaq (%rbx,%rbx), %rsi
testq %rbx, %rbx
movl $0x2, %eax
cmoveq %rax, %rsi
movq %rsi, 0x8(%r8)
shlq $0x5, %rsi
movq %r14, %rdi
callq 0x2350
movq 0x18(%rsp), %r8
movq %rax, %r14
movq %rax, 0x10(%r8)
movq (%r8), %rbx
leaq 0x1(%rbx), %rax
movq %rax, (%r8)
shlq $0x5, %rbx
movq 0x30(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, (%r14,%rbx)
movq $-0x1, 0x8(%r14,%rbx)
movl $0x0, 0x10(%r14,%rbx)
movl (%rbp,%r12,4), %edi
shlq $0x3, %rdi
callq 0x2310
movq 0x18(%rsp), %r8
movq %rax, 0x18(%r14,%rbx)
incq %r12
cmpq %r12, %r15
jne 0x10017
cmpb $0x0, 0x10(%rsp)
movq 0x30(%rsp), %rdx
movq 0x40(%rsp), %r15
movq 0x38(%rsp), %r12
jne 0x1016c
xorl %eax, %eax
movq (%r8), %rdi
subq %r13, %rdi
movq 0x28(%rsp), %rcx
movslq (%rcx,%rax,4), %r14
shlq $0x5, %rdi
addq 0x10(%r8), %rdi
movq %r14, %r8
shlq $0x5, %r8
movq (%rdx), %rcx
leaq (%r8,%rdi), %rsi
addq $0x8, %rsi
movq 0x10(%rsi), %r9
movl 0x8(%rsi), %r10d
movl %r10d, %r11d
andl $0x7fffffff, %r11d      # imm = 0x7FFFFFFF
leal 0x1(%r10), %ebx
andl $0x7fffffff, %ebx       # imm = 0x7FFFFFFF
andl $0x80000000, %r10d      # imm = 0x80000000
orl %ebx, %r10d
movl %r10d, 0x8(%rsi)
movq %rcx, (%r9,%r11,8)
movq 0x10(%r15), %r9
movq (%rdx), %r10
movq %r10, %rcx
shrq $0x20, %rcx
imulq $0x58, %rcx, %r11
movq 0x48(%r9,%r11), %rcx
shrl %r10d
movq (%rcx,%r10,8), %rcx
movq (%rsi), %rbx
cmpq $-0x1, %rbx
je 0x10142
cmpq %rcx, %rbx
je 0x10145
jmp 0x101a1
movq %rcx, (%rsi)
subq %r13, %r14
movq 0x18(%rsp), %r8
addq (%r8), %r14
addq %r14, %r14
movq 0x50(%r9,%r11), %rcx
movq %r14, (%rcx,%r10,8)
incq %rax
addq $0x10, %rdx
cmpq %rax, %r12
jne 0x100bd
movq %rbp, %rdi
callq 0x2060
movq 0x28(%rsp), %rdi
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2060
movb $0x1, %al
movl %eax, 0x10(%rsp)
movq 0x18(%rsp), %r8
movq 0x8(%rsp), %rsi
jmp 0x10009
addq %r8, %rdi
callq 0x29be