// File: /workspace/github_c_makefile_star2_O1/samtools[P]htslib/htscodecs/htscodecs/rANS_static32x16pr_avx512.c
// Function: rans_uncompress_O0_32x16_avx512
unsigned char *rans_uncompress_O0_32x16_avx512(unsigned char *in,
                                               unsigned int in_size,
                                               unsigned char *out,
                                               unsigned int out_sz) {
    if (in_size < 32*4) // 32-states at least
        return NULL;

    if (out_sz >= INT_MAX)
        return NULL; // protect against some overflow cases

    /* Load in the static tables */
    unsigned char *cp = in, *out_free = NULL;
    unsigned char *cp_end = in + in_size;
    int i;
    uint32_t s3[TOTFREQ]  __attribute__((aligned(64))); // For TF_SHIFT <= 12

    if (!out)
        out_free = out = malloc(out_sz);
    if (!out)
        return NULL;

    // Precompute reverse lookup of frequency.
    uint32_t F[256] = {0}, fsum;
    int fsz = decode_freq(cp, cp_end, F, &fsum);
    if (!fsz)
        goto err;
    cp += fsz;

    normalise_freq_shift(F, fsum, TOTFREQ);

    // Build symbols; fixme, do as part of decode, see the _d variant
    if (rans_F_to_s3(F, TF_SHIFT, s3))
        goto err;

    if (cp_end - cp < 32 * 4)
        goto err;

    int z;
    RansState Rv[32] __attribute__((aligned(64)));
    for (z = 0; z < 32; z++) {
        RansDecInit(&Rv[z], &cp);
        if (Rv[z] < RANS_BYTE_L)
            goto err;
    }

    uint16_t *sp = (uint16_t *)cp;

    int out_end = (out_sz&~(32-1));
    const uint32_t mask = (1u << TF_SHIFT)-1;

    __m512i maskv = _mm512_set1_epi32(mask); // set mask in all lanes
    __m512i R1 = _mm512_load_epi32(&Rv[0]);
    __m512i R2 = _mm512_load_epi32(&Rv[16]);

    // Start of the first loop iteration, which we do move to the end of the
    // loop for the next cycle so we can remove some of the instr. latency.
    __m512i masked1 = _mm512_and_epi32(R1, maskv);
    __m512i masked2 = _mm512_and_epi32(R2, maskv);
    __m512i S1 = _mm512_i32gather_epi32x(masked1, (int *)s3, sizeof(*s3));
    __m512i S2 = _mm512_i32gather_epi32x(masked2, (int *)s3, sizeof(*s3));

    uint8_t overflow[64+64] = {0};
    for (i=0; i < out_end; i+=32) {
      //for (z = 0; z < 16; z++) {

      // Protect against running off the end of in buffer.
      // We copy it to a worst-case local buffer when near the end.
      if ((uint8_t *)sp+64 > cp_end) {
        memmove(overflow, sp, cp_end - (uint8_t *)sp);
        sp = (uint16_t *)overflow;
        cp_end = overflow + sizeof(overflow);
      }

      //uint32_t S = s3[R[z] & mask];
      __m512i renorm_words1 = _mm512_cvtepu16_epi32(_mm256_loadu_si256((const __m256i *)sp)); // next 16 words

      //uint16_t f = S>>(TF_SHIFT+8), b = (S>>8) & mask;
      __m512i f1 = _mm512_srli_epi32(S1, TF_SHIFT+8);
      __m512i f2 = _mm512_srli_epi32(S2, TF_SHIFT+8);
      __m512i b1 = _mm512_and_epi32(_mm512_srli_epi32(S1, 8), maskv);
      __m512i b2 = _mm512_and_epi32(_mm512_srli_epi32(S2, 8), maskv);

      //R[z] = f * (R[z] >> TF_SHIFT) + b;
      // approx 10 cycle latency on mullo.
      R1 = _mm512_add_epi32(
               _mm512_mullo_epi32(
                   _mm512_srli_epi32(R1, TF_SHIFT), f1), b1);
      __mmask16 renorm_mask1, renorm_mask2;
      renorm_mask1=_mm512_cmplt_epu32_mask(R1, _mm512_set1_epi32(RANS_BYTE_L));
      R2 = _mm512_add_epi32(
               _mm512_mullo_epi32(
                   _mm512_srli_epi32(R2, TF_SHIFT), f2), b2);

      // renorm. this is the interesting part:
      renorm_mask2=_mm512_cmplt_epu32_mask(R2, _mm512_set1_epi32(RANS_BYTE_L));
      // advance by however many words we actually read
      sp += _mm_popcnt_u32(renorm_mask1);
      __m512i renorm_words2 = _mm512_cvtepu16_epi32(_mm256_loadu_si256(
                                      (const __m256i *)sp));

      // select masked only
      __m512i renorm_vals1, renorm_vals2;

      renorm_vals1 = _mm512_mask_expand_epi32(R1, renorm_mask1, renorm_words1);
      renorm_vals2 = _mm512_mask_expand_epi32(R2, renorm_mask2, renorm_words2);

      // For start of next loop iteration.  This has been moved here
      // (and duplicated to before the loop starts) so we can do something
      // with the latency period of gather, such as finishing up the
      // renorm offset and writing the results.
      __m512i S1_ = S1; // temporary copy for use in out[]=S later
      __m512i S2_ = S2;

      masked1 = _mm512_and_epi32(renorm_vals1, maskv);
      S1 = _mm512_i32gather_epi32x(masked1, (int *)s3, sizeof(*s3));
      masked2 = _mm512_and_epi32(renorm_vals2, maskv);
      S2 = _mm512_i32gather_epi32x(masked2, (int *)s3, sizeof(*s3));

      R1 = _mm512_mask_slli_epi32(R1, renorm_mask1, R1, 16);
      R2 = _mm512_mask_slli_epi32(R2, renorm_mask2, R2, 16);

      __m512i m16 = _mm512_set1_epi32(0xffff);
      renorm_vals1 = _mm512_maskz_and_epi32(renorm_mask1, renorm_vals1, m16);
      renorm_vals2 = _mm512_maskz_and_epi32(renorm_mask2, renorm_vals2, m16);

      // advance by however many words we actually read
      sp += _mm_popcnt_u32(renorm_mask2);

      R1 = _mm512_add_epi32(R1, renorm_vals1);
      R2 = _mm512_add_epi32(R2, renorm_vals2);

      //out[i+z] = S;
      _mm_storeu_si128((__m128i *)(out+i),    _mm512_cvtepi32_epi8(S1_));
      _mm_storeu_si128((__m128i *)(out+i+16), _mm512_cvtepi32_epi8(S2_));
    }

    _mm512_store_epi32(&Rv[ 0], R1);
    _mm512_store_epi32(&Rv[16], R2);

    for (z = out_sz & (32-1); z-- > 0; )
      out[out_end + z] = s3[Rv[z] & mask];

    return out;

 err:
    free(out_free);
    return NULL;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
andq $-0x40, %rsp
subq $0x4680, %rsp           # imm = 0x4680
movl %ecx, %r15d
cmpl $0x80, %esi
setb %al
cmpl $0x7fffffff, %ecx       # imm = 0x7FFFFFFF
setae %cl
orb %al, %cl
jne 0x704a4
movl %esi, %r13d
movq %rdi, %r14
testq %rdx, %rdx
je 0x6fd42
xorl %eax, %eax
jmp 0x6fd4d
movl %r15d, %edi
callq 0x4680
movq %rax, %rdx
xorl %ebx, %ebx
testq %rdx, %rdx
je 0x704a4
movq %r15, 0x30(%rsp)
movq %rax, 0x80(%rsp)
movq %rdx, 0x28(%rsp)
movl %r13d, %eax
movq %rax, 0x40(%rsp)
leaq (%r14,%rax), %r15
leaq 0x240(%rsp), %rdi
movl $0x400, %edx            # imm = 0x400
xorl %esi, %esi
callq 0x4260
testl %r13d, %r13d
je 0x6ff10
leaq 0x1(%r14), %rax
movzbl (%r14), %ecx
xorl %edx, %edx
cmpl $0x4, %r13d
jb 0x6fdf1
xorl %ebx, %ebx
xorl %edx, %edx
movl %ecx, %esi
movl $0x1, 0x240(%rsp,%rsi,4)
testl %edx, %edx
je 0x6fdca
cmpl $0xfe, %ecx
jg 0x6fe4d
decl %edx
incl %ecx
jmp 0x6fde4
movl %ecx, %edx
incl %edx
movzbl (%rax), %ecx
cmpl %ecx, %edx
jne 0x6fddf
movzbl 0x1(%rax), %edx
addq $0x2, %rax
jmp 0x6fde4
incq %rax
xorl %edx, %edx
testl %ecx, %ecx
je 0x6fdf1
leaq 0x2(%rax), %rsi
cmpq %r15, %rsi
jb 0x6fda7
testl %ecx, %ecx
je 0x6fe47
xorl %ebx, %ebx
movl %ecx, %esi
movl $0x1, 0x240(%rsp,%rsi,4)
cmpq %r15, %rax
jae 0x6fe4d
testl %edx, %edx
je 0x6fe1b
cmpl $0xfe, %ecx
jg 0x6fe4d
decl %edx
incl %ecx
jmp 0x6fe3e
movl %ecx, %edi
incl %edi
movzbl (%rax), %ecx
leaq 0x1(%rax), %rsi
xorl %edx, %edx
cmpl %ecx, %edi
jne 0x6fe3b
cmpq %r15, %rsi
jae 0x6fe4d
movzbl 0x1(%rax), %edx
addq $0x2, %rax
jmp 0x6fe3e
movq %rsi, %rax
testl %ecx, %ecx
je 0x6fe47
cmpq %r15, %rax
jb 0x6fdf7
subl %r14d, %eax
movslq %eax, %rbx
addq %r14, %rbx
xorl %ecx, %ecx
xorl %eax, %eax
cmpl $0x0, 0x240(%rsp,%rcx,4)
je 0x6fed3
movq %r15, %rdx
subq %rbx, %rdx
cmpq $0x6, %rdx
jl 0x6fea2
xorl %edi, %edi
xorl %edx, %edx
movzbl (%rbx,%rdi), %r8d
movl %edx, %esi
shll $0x7, %esi
movl %r8d, %edx
andl $0x7f, %edx
orl %esi, %edx
leaq 0x1(%rdi), %rsi
testb %r8b, %r8b
jns 0x6fe91
cmpl $0x5, %edi
movq %rsi, %rdi
jne 0x6fe6e
addq %rbx, %rsi
movl %edx, 0x240(%rsp,%rcx,4)
subl %ebx, %esi
movslq %esi, %rdx
jmp 0x6fec9
cmpq %r15, %rbx
jae 0x6febc
movsbl (%rbx), %edx
testl %edx, %edx
js 0x6fee5
movl %edx, 0x240(%rsp,%rcx,4)
movl $0x1, %edx
jmp 0x6fec9
movl $0x0, 0x240(%rsp,%rcx,4)
xorl %edx, %edx
addq %rdx, %rbx
addl 0x240(%rsp,%rcx,4), %eax
incq %rcx
cmpq $0x100, %rcx            # imm = 0x100
jne 0x6fe54
jmp 0x6ff0b
xorl %edx, %edx
movq %rbx, %rsi
movzbl (%rsi), %edi
incq %rsi
movl %edx, %r8d
shll $0x7, %r8d
movl %edi, %edx
andl $0x7f, %edx
orl %r8d, %edx
testb %dil, %dil
jns 0x6fe94
cmpq %r15, %rsi
jb 0x6feea
jmp 0x6fe94
subl %r14d, %ebx
jmp 0x6ff10
testl %ebx, %ebx
je 0x70497
movslq %ebx, %rdx
testl $0xffffefff, %eax       # imm = 0xFFFFEFFF
je 0x6ff4f
xorl %ecx, %ecx
cmpl $0xfff, %eax            # imm = 0xFFF
ja 0x6ff3b
xorl %ecx, %ecx
leal (%rax,%rax), %esi
incl %ecx
cmpl $0x800, %eax            # imm = 0x800
movl %esi, %eax
jb 0x6ff2d
xorl %eax, %eax
shll %cl, 0x240(%rsp,%rax,4)
incq %rax
cmpq $0x100, %rax            # imm = 0x100
jne 0x6ff3d
addq %rdx, %r14
xorl %eax, %eax
xorl %ecx, %ecx
movl 0x240(%rsp,%rax,4), %esi
movl $0x1000, %edi           # imm = 0x1000
subl %ecx, %edi
leal -0x1(%rsi), %r8d
cmpl %edi, %r8d
jae 0x6ff8e
testl %esi, %esi
je 0x6ff8e
movl %esi, %edi
shll $0x14, %edi
addl %eax, %edi
movslq %ecx, %rcx
movl %edi, 0x640(%rsp,%rcx,4)
incl %ecx
addl $0x100, %edi            # imm = 0x100
decl %esi
jne 0x6ff78
incq %rax
cmpq $0x100, %rax            # imm = 0x100
jne 0x6ff56
cmpl $0x1000, %ecx           # imm = 0x1000
jne 0x70497
movq 0x40(%rsp), %rax
subq %rdx, %rax
cmpq $0x80, %rax
jl 0x70497
xorl %ebx, %ebx
movl (%r14,%rbx), %eax
movl %eax, 0x140(%rsp,%rbx)
cmpl $0x8000, %eax           # imm = 0x8000
jb 0x70497
addq $0x4, %rbx
cmpq $0x80, %rbx
jne 0x6ffbb
movq 0x30(%rsp), %r13
andl $0x7fffffe0, %r13d      # imm = 0x7FFFFFE0
vmovdqa64 0x140(%rsp), %zmm0
vmovdqa64 0x180(%rsp), %zmm1
vpbroadcastq 0x2ecb4(%rip), %zmm2 # 0x9ecb8
vmovdqa64 %zmm0, 0x80(%rsp)
vpandq %zmm2, %zmm0, %zmm0
vmovdqa64 %zmm1, 0x40(%rsp)
vpandq %zmm2, %zmm1, %zmm1
vmovdqa64 %zmm1, 0xc0(%rsp)
leaq 0x640(%rsp), %r12
movq %r12, %rdi
callq 0x6fbec
vmovdqa64 %zmm0, 0x100(%rsp)
vmovdqa64 0xc0(%rsp), %zmm0
movq %r12, %rdi
callq 0x6fbec
vpxor %xmm1, %xmm1, %xmm1
vmovdqa64 %zmm1, 0x1c0(%rsp)
vmovdqa64 %zmm1, 0x200(%rsp)
testl %r13d, %r13d
je 0x704b8
addq %rbx, %r14
movq %r13, 0x38(%rsp)
movl %r13d, %r13d
xorl %ebx, %ebx
vpbroadcastd 0x2ec20(%rip), %zmm15 # 0x9eca4
vpbroadcastd 0x32c76(%rip), %zmm16 # 0xa2d04
vpbroadcastd 0x32c68(%rip), %zmm17 # 0xa2d00
movq 0x28(%rsp), %rax
vmovdqa64 0x80(%rsp), %zmm11
vmovdqa64 0x40(%rsp), %zmm12
vmovdqa64 0x100(%rsp), %zmm13
leaq 0x40(%r14), %rcx
cmpq %r15, %rcx
jbe 0x7014c
subq %r14, %r15
leaq 0x1c0(%rsp), %r12
movq %r12, %rdi
movq %r14, %rsi
movq %r15, %rdx
vmovdqa64 %zmm11, 0x80(%rsp)
vmovdqa64 %zmm12, 0x40(%rsp)
vmovdqa64 %zmm13, 0x100(%rsp)
vmovdqa64 %zmm0, 0xc0(%rsp)
vzeroupper
callq 0x4830
vpbroadcastd 0x32bf8(%rip), %zmm17 # 0xa2d00
vpbroadcastd 0x32bf2(%rip), %zmm16 # 0xa2d04
vpbroadcastd 0x2eb88(%rip), %zmm15 # 0x9eca4
vmovdqa64 0xc0(%rsp), %zmm0
vmovdqa64 0x100(%rsp), %zmm13
vmovdqa64 0x40(%rsp), %zmm12
vmovdqa64 0x80(%rsp), %zmm11
movq 0x28(%rsp), %rax
movq %r12, %r14
leaq 0x240(%rsp), %r15
vpmovzxwd (%r14), %zmm1
vpsrld $0x14, %zmm13, %zmm6
vpsrld $0x14, %zmm0, %zmm2
vpsrld $0x8, %zmm13, %zmm3
vpsrld $0x8, %zmm0, %zmm4
vpsrld $0xc, %zmm11, %zmm5
vpmulld %zmm6, %zmm5, %zmm5
vpandd %zmm15, %zmm3, %zmm3
vpaddd %zmm3, %zmm5, %zmm11
vpcmpltud %zmm16, %zmm11, %k1
vpsrld $0xc, %zmm12, %zmm3
vpmulld %zmm2, %zmm3, %zmm3
vpandd %zmm15, %zmm4, %zmm2
vpaddd %zmm2, %zmm3, %zmm12
vpcmpltud %zmm16, %zmm12, %k2
kmovw %k1, %ecx
popcntl %ecx, %ecx
leaq (%r14,%rcx,2), %rdx
vpmovzxwd (%rdx), %zmm2
vmovdqa64 %zmm11, %zmm14
vpexpandd %zmm1, %zmm14 {%k1}
vmovdqa64 %zmm12, %zmm1
vpexpandd %zmm2, %zmm1 {%k2}
vpbroadcastq 0x2ead6(%rip), %zmm7 # 0x9ecb8
vpandq %zmm7, %zmm14, %zmm5
vextracti128 $0x1, %ymm5, %xmm4
vextracti32x4 $0x2, %zmm5, %xmm3
vextracti32x4 $0x3, %zmm5, %xmm2
vmovd %xmm2, %ecx
vmovd 0x640(%rsp,%rcx,4), %xmm6
vpextrd $0x1, %xmm2, %ecx
vpinsrd $0x1, 0x640(%rsp,%rcx,4), %xmm6, %xmm6
vpextrd $0x2, %xmm2, %ecx
vpinsrd $0x2, 0x640(%rsp,%rcx,4), %xmm6, %xmm6
vpextrd $0x3, %xmm2, %ecx
vpinsrd $0x3, 0x640(%rsp,%rcx,4), %xmm6, %xmm2
vmovd %xmm3, %ecx
vmovd 0x640(%rsp,%rcx,4), %xmm6
vpextrd $0x1, %xmm3, %ecx
vpinsrd $0x1, 0x640(%rsp,%rcx,4), %xmm6, %xmm6
vpextrd $0x2, %xmm3, %ecx
vpinsrd $0x2, 0x640(%rsp,%rcx,4), %xmm6, %xmm6
vpextrd $0x3, %xmm3, %ecx
vpinsrd $0x3, 0x640(%rsp,%rcx,4), %xmm6, %xmm3
vmovd %xmm4, %ecx
vmovd 0x640(%rsp,%rcx,4), %xmm6
vpextrd $0x1, %xmm4, %ecx
vpinsrd $0x1, 0x640(%rsp,%rcx,4), %xmm6, %xmm6
vpextrd $0x2, %xmm4, %ecx
vpinsrd $0x2, 0x640(%rsp,%rcx,4), %xmm6, %xmm6
vpextrd $0x3, %xmm4, %ecx
vpinsrd $0x3, 0x640(%rsp,%rcx,4), %xmm6, %xmm4
vmovd %xmm5, %ecx
vmovd 0x640(%rsp,%rcx,4), %xmm6
vpextrd $0x1, %xmm5, %ecx
vpinsrd $0x1, 0x640(%rsp,%rcx,4), %xmm6, %xmm6
vpextrd $0x2, %xmm5, %ecx
vpinsrd $0x2, 0x640(%rsp,%rcx,4), %xmm6, %xmm6
vpextrd $0x3, %xmm5, %ecx
vpinsrd $0x3, 0x640(%rsp,%rcx,4), %xmm6, %xmm5
vpandq %zmm7, %zmm1, %zmm6
vextracti128 $0x1, %ymm6, %xmm7
vextracti32x4 $0x2, %zmm6, %xmm9
vextracti32x4 $0x3, %zmm6, %xmm8
vmovd %xmm8, %ecx
vmovd 0x640(%rsp,%rcx,4), %xmm10
vpextrd $0x1, %xmm8, %ecx
vpinsrd $0x1, 0x640(%rsp,%rcx,4), %xmm10, %xmm10
vpextrd $0x2, %xmm8, %ecx
vpinsrd $0x2, 0x640(%rsp,%rcx,4), %xmm10, %xmm10
vpextrd $0x3, %xmm8, %ecx
vpinsrd $0x3, 0x640(%rsp,%rcx,4), %xmm10, %xmm8
vmovd %xmm9, %ecx
vmovd 0x640(%rsp,%rcx,4), %xmm10
vpextrd $0x1, %xmm9, %ecx
vpinsrd $0x1, 0x640(%rsp,%rcx,4), %xmm10, %xmm10
vpextrd $0x2, %xmm9, %ecx
vpinsrd $0x2, 0x640(%rsp,%rcx,4), %xmm10, %xmm10
vpextrd $0x3, %xmm9, %ecx
vpinsrd $0x3, 0x640(%rsp,%rcx,4), %xmm10, %xmm9
vmovd %xmm7, %ecx
vmovd 0x640(%rsp,%rcx,4), %xmm10
vpextrd $0x1, %xmm7, %ecx
vpinsrd $0x1, 0x640(%rsp,%rcx,4), %xmm10, %xmm10
vpextrd $0x2, %xmm7, %ecx
vpinsrd $0x2, 0x640(%rsp,%rcx,4), %xmm10, %xmm10
vpextrd $0x3, %xmm7, %ecx
vpinsrd $0x3, 0x640(%rsp,%rcx,4), %xmm10, %xmm7
vmovd %xmm6, %ecx
vmovd 0x640(%rsp,%rcx,4), %xmm10
vpextrd $0x1, %xmm6, %ecx
vpinsrd $0x1, 0x640(%rsp,%rcx,4), %xmm10, %xmm10
vpextrd $0x2, %xmm6, %ecx
vpinsrd $0x2, 0x640(%rsp,%rcx,4), %xmm10, %xmm10
vpextrd $0x3, %xmm6, %ecx
vpinsrd $0x3, 0x640(%rsp,%rcx,4), %xmm10, %xmm6
kmovw %k2, %ecx
popcntl %ecx, %ecx
leaq (%rdx,%rcx,2), %r14
vinserti128 $0x1, %xmm2, %ymm3, %ymm2
vinserti128 $0x1, %xmm4, %ymm5, %ymm3
vpmovdb %zmm13, (%rax,%rbx)
vinserti64x4 $0x1, %ymm2, %zmm3, %zmm13
vinserti128 $0x1, %xmm8, %ymm9, %ymm3
vpmovdb %zmm0, 0x10(%rax,%rbx)
vinserti128 $0x1, %xmm7, %ymm6, %ymm4
vinserti64x4 $0x1, %ymm3, %zmm4, %zmm3
vpslld $0x10, %zmm11, %zmm4
vpslld $0x10, %zmm12, %zmm5
vpandq %zmm17, %zmm14, %zmm0
vpandq %zmm17, %zmm1, %zmm1
vpord %zmm4, %zmm0, %zmm11 {%k1}
vpord %zmm5, %zmm1, %zmm12 {%k2}
addq $0x20, %rbx
vmovdqa64 %zmm3, %zmm0
cmpq %r13, %rbx
jb 0x700b5
movq 0x38(%rsp), %r13
jmp 0x704cd
movq 0x80(%rsp), %rdi
callq 0x45c0
xorl %eax, %eax
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
vzeroupper
retq
movq 0x28(%rsp), %rax
vmovdqa64 0x80(%rsp), %zmm11
vmovdqa64 0x40(%rsp), %zmm12
vmovdqa64 %zmm11, 0x140(%rsp)
vmovdqa64 %zmm12, 0x180(%rsp)
movq 0x30(%rsp), %rsi
testb $0x1f, %sil
je 0x704a6
andl $0x1f, %esi
incq %rsi
addq %rax, %r13
movl $0xfff, %edx            # imm = 0xFFF
movl 0x138(%rsp,%rsi,4), %ecx
andl %edx, %ecx
movb 0x640(%rsp,%rcx,4), %cl
movb %cl, -0x2(%r13,%rsi)
decq %rsi
cmpq $0x1, %rsi
jg 0x704f6
jmp 0x704a6