// File: /workspace/github_c_makefile_star2_O1/samtools[P]htslib/cram/cram_decode.c
// Function: cram_decode_slice_xref
static int cram_decode_slice_xref(cram_slice *s, int required_fields) {
    int rec;

    if (!(required_fields & (SAM_RNEXT | SAM_PNEXT | SAM_TLEN))) {
        for (rec = 0; rec < s->hdr->num_records; rec++) {
            cram_record *cr = &s->crecs[rec];

            cr->tlen = 0;
            cr->mate_pos = 0;
            cr->mate_ref_id = -1;
        }

        return 0;
    }

    for (rec = 0; rec < s->hdr->num_records; rec++) {
        cram_record *cr = &s->crecs[rec];

        if (cr->mate_line >= 0) {
            if (cr->mate_line < s->hdr->num_records) {
                /*
                 * On the first read, loop through computing lengths.
                 * It's not perfect as we have one slice per reference so we
                 * cannot detect when TLEN should be zero due to seqs that
                 * map to multiple references.
                 *
                 * We also cannot set tlen correct when it spans a slice for
                 * other reasons. This may make tlen too small. Should we
                 * fix this by forcing TLEN to be stored verbatim in such cases?
                 *
                 * Or do we just admit defeat and output 0 for tlen? It's the
                 * safe option...
                 */
                if (cr->tlen == INT64_MIN) {
                    int id1 = rec, id2 = rec;
                    int64_t aleft = cr->apos, aright = cr->aend;
                    int64_t tlen;
                    int ref = cr->ref_id;

                    // number of segments starting at the same point.
                    int left_cnt = 0;

                    do {
                        if (aleft > s->crecs[id2].apos)
                            aleft = s->crecs[id2].apos, left_cnt = 1;
                        else if (aleft == s->crecs[id2].apos)
                            left_cnt++;
                        if (aright < s->crecs[id2].aend)
                            aright = s->crecs[id2].aend;
                        if (s->crecs[id2].mate_line == -1) {
                            s->crecs[id2].mate_line = rec;
                            break;
                        }
                        if (s->crecs[id2].mate_line <= id2 ||
                            s->crecs[id2].mate_line >= s->hdr->num_records)
                            return -1;
                        id2 = s->crecs[id2].mate_line;

                        if (s->crecs[id2].ref_id != ref)
                            ref = -1;
                    } while (id2 != id1);

                    if (ref != -1) {
                        tlen = aright - aleft + 1;
                        id1 = id2 = rec;

                        /*
                         * When we have two seqs with identical start and
                         * end coordinates, set +/- tlen based on 1st/last
                         * bit flags instead, as a tie breaker.
                         */
                        if (s->crecs[id2].apos == aleft) {
                            if (left_cnt == 1 ||
                                (s->crecs[id2].flags & BAM_FREAD1))
                                s->crecs[id2].tlen = tlen;
                            else
                                s->crecs[id2].tlen = -tlen;
                        } else {
                            s->crecs[id2].tlen = -tlen;
                        }

                        id2 = s->crecs[id2].mate_line;
                        while (id2 != id1) {
                            if (s->crecs[id2].apos == aleft) {
                                if (left_cnt == 1 ||
                                    (s->crecs[id2].flags & BAM_FREAD1))
                                    s->crecs[id2].tlen = tlen;
                                else
                                    s->crecs[id2].tlen = -tlen;
                            } else {
                                s->crecs[id2].tlen = -tlen;
                            }
                            id2 = s->crecs[id2].mate_line;
                        }
                    } else {
                        id1 = id2 = rec;

                        s->crecs[id2].tlen = 0;
                        id2 = s->crecs[id2].mate_line;
                        while (id2 != id1) {
                            s->crecs[id2].tlen = 0;
                            id2 = s->crecs[id2].mate_line;
                        }
                    }
                }

                cr->mate_pos = s->crecs[cr->mate_line].apos;
                cr->mate_ref_id = s->crecs[cr->mate_line].ref_id;

                // paired
                cr->flags |= BAM_FPAIRED;

                // set mate unmapped if needed
                if (s->crecs[cr->mate_line].flags & BAM_FUNMAP) {
                    cr->flags |= BAM_FMUNMAP;
                    cr->tlen = 0;
                }
                if (cr->flags & BAM_FUNMAP) {
                    cr->tlen = 0;
                }

                // set mate reversed if needed
                if (s->crecs[cr->mate_line].flags & BAM_FREVERSE)
                    cr->flags |= BAM_FMREVERSE;
            } else {
                hts_log_error("Mate line out of bounds: %d vs [0, %d]",
                              cr->mate_line, s->hdr->num_records-1);
            }

            /* FIXME: construct read names here too if needed */
        } else {
            if (cr->mate_flags & CRAM_M_REVERSE) {
                cr->flags |= BAM_FPAIRED | BAM_FMREVERSE;
            }
            if (cr->mate_flags & CRAM_M_UNMAP) {
                cr->flags |= BAM_FMUNMAP;
                //cr->mate_ref_id = -1;
            }
            if (!(cr->flags & BAM_FPAIRED))
                cr->mate_ref_id = -1;
        }

        if (cr->tlen == INT64_MIN)
            cr->tlen = 0; // Just incase
    }

    for (rec = 0; rec < s->hdr->num_records; rec++) {
        cram_record *cr = &s->crecs[rec];
        if (cr->explicit_tlen != INT64_MIN)
            cr->tlen = cr->explicit_tlen;
    }

    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
movq %rdi, %rbx
movq (%rdi), %rax
movl 0x18(%rax), %r8d
testl $0x1c0, %esi            # imm = 0x1C0
je 0x3f32c
movabsq $-0x8000000000000000, %r12 # imm = 0x8000000000000000
testl %r8d, %r8d
jle 0x3f2f9
leaq 0x5d517(%rip), %r13     # 0x9c58d
leaq 0x5d527(%rip), %rbp     # 0x9c5a4
xorl %r14d, %r14d
movq 0x30(%rbx), %rdx
leaq (%r14,%r14,8), %r9
shlq $0x4, %r9
leaq (%rdx,%r9), %r15
movl 0x2c(%rdx,%r9), %ecx
testl %ecx, %ecx
js 0x3f158
cmpl %r8d, %ecx
jge 0x3f189
cmpq %r12, 0x40(%r15)
jne 0x3f22b
movq 0x18(%r15), %rsi
movq 0x78(%r15), %rdi
movl 0x8(%r15), %r11d
xorl %ecx, %ecx
movl %r14d, %r13d
movq %rsi, (%rsp)
movq %rdi, %rbp
movq %rsi, %rdi
movslq %r13d, %rax
leaq (%rax,%rax,8), %rax
shlq $0x4, %rax
movq 0x18(%rdx,%rax), %rsi
xorl %r10d, %r10d
cmpq %rsi, %rdi
sete %r10b
addl %r10d, %ecx
cmpq %rsi, %rdi
cmovlq %rdi, %rsi
movq 0x78(%rdx,%rax), %rdi
movl $0x1, %r10d
cmovgl %r10d, %ecx
cmpq %rdi, %rbp
cmovgq %rbp, %rdi
movslq 0x2c(%rdx,%rax), %rbp
cmpq $-0x1, %rbp
je 0x3f1a3
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
cmpl %r13d, %ebp
jle 0x3f364
cmpl %r8d, %ebp
jge 0x3f364
leaq (,%rbp,8), %rax
addq %rbp, %rax
shlq $0x4, %rax
cmpl %r11d, 0x8(%rdx,%rax)
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
cmovnel %eax, %r11d
movl %ebp, %eax
movl %ebp, %r13d
cmpq %rax, %r14
jne 0x3f0c5
jmp 0x3f1ad
movl 0x8c(%r15), %eax
testb $0x1, %al
je 0x3f168
orb $0x21, 0xc(%r15)
testb $0x2, %al
je 0x3f171
orb $0x8, 0xc(%r15)
testb $0x1, 0xc(%r15)
jne 0x3f28f
movl $0xffffffff, 0x30(%r15) # imm = 0xFFFFFFFF
jmp 0x3f28f
decl %r8d
movl $0x1, %edi
movq %r13, %rsi
movq %rbp, %rdx
xorl %eax, %eax
callq 0x14378
jmp 0x3f28f
addq %rdx, %rax
addq $0x2c, %rax
movl %r14d, (%rax)
cmpl $-0x1, %r11d
je 0x3f1ee
subq %rsi, %rdi
leaq 0x1(%rdi), %rax
notq %rdi
cmpq %rsi, (%rsp)
leaq 0x5d3c5(%rip), %r13     # 0x9c58d
leaq 0x5d3d5(%rip), %rbp     # 0x9c5a4
jne 0x3f1e5
cmpl $0x1, %ecx
je 0x3f2b2
testb $0x40, 0xc(%r15)
jne 0x3f2b2
movq %rdi, 0x40(%r15)
jmp 0x3f2b7
movq $0x0, 0x40(%rdx,%r9)
movl 0x2c(%rdx,%r9), %eax
cmpq %rax, %r14
leaq 0x5d387(%rip), %r13     # 0x9c58d
leaq 0x5d397(%rip), %rbp     # 0x9c5a4
je 0x3f22b
cltq
leaq (%rax,%rax,8), %rax
shlq $0x4, %rax
movq $0x0, 0x40(%rdx,%rax)
movl 0x2c(%rdx,%rax), %eax
cmpq %rax, %r14
jne 0x3f20f
movslq 0x2c(%r15), %rax
leaq (%rax,%rax,8), %rax
shlq $0x4, %rax
movq 0x18(%rdx,%rax), %rcx
movq %rcx, 0x38(%r15)
movl 0x8(%rdx,%rax), %ecx
movl %ecx, 0x30(%r15)
movl 0xc(%r15), %ecx
movl %ecx, %esi
orl $0x1, %esi
movl %esi, 0xc(%r15)
testb $0x4, 0xc(%rdx,%rax)
je 0x3f26b
orl $0x9, %ecx
movl %ecx, 0xc(%r15)
movq $0x0, 0x40(%r15)
movl 0xc(%r15), %ecx
testb $0x4, %cl
je 0x3f27c
movq $0x0, 0x40(%r15)
addq %rdx, %rax
addq $0xc, %rax
testb $0x10, (%rax)
je 0x3f28f
orl $0x20, %ecx
movl %ecx, 0xc(%r15)
cmpq %r12, 0x40(%r15)
jne 0x3f29d
movq $0x0, 0x40(%r15)
incq %r14
movq (%rbx), %rax
movslq 0x18(%rax), %r8
cmpq %r8, %r14
jl 0x3f080
jmp 0x3f2f9
movq %rax, 0x40(%rdx,%r9)
movl 0x2c(%rdx,%r9), %r8d
cmpq %r8, %r14
je 0x3f22b
movslq %r8d, %r8
leaq (%r8,%r8,8), %r8
shlq $0x4, %r8
leaq (%rdx,%r8), %r9
cmpq %rsi, 0x18(%rdx,%r8)
jne 0x3f2e7
cmpl $0x1, %ecx
je 0x3f2ed
testb $0x40, 0xc(%r9)
jne 0x3f2ed
movq %rdi, 0x40(%r9)
jmp 0x3f2f2
movq %rax, 0x40(%rdx,%r8)
movl 0x2c(%rdx,%r8), %r8d
jmp 0x3f2bc
testl %r8d, %r8d
jle 0x3f362
movq 0x30(%rbx), %rax
movl %r8d, %ecx
shlq $0x4, %rcx
leaq (%rcx,%rcx,8), %rcx
xorl %edx, %edx
movq 0x48(%rax,%rdx), %rsi
cmpq %r12, %rsi
je 0x3f31e
movq %rsi, 0x40(%rax,%rdx)
addq $0x90, %rdx
cmpq %rdx, %rcx
jne 0x3f30f
jmp 0x3f362
testl %r8d, %r8d
jle 0x3f362
movq 0x30(%rbx), %rcx
addq $0x38, %rcx
shlq $0x4, %r8
leaq (%r8,%r8,8), %rdx
xorl %eax, %eax
xorps %xmm0, %xmm0
xorl %esi, %esi
movups %xmm0, (%rcx,%rsi)
movl $0xffffffff, -0x8(%rcx,%rsi) # imm = 0xFFFFFFFF
addq $0x90, %rsi
cmpq %rsi, %rdx
jne 0x3f348
jmp 0x3f364
xorl %eax, %eax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq