// File: /workspace/github_cpp_makefile_star2_O1/lukasz-wiecaszek[P]h264iframedecoder/picture_cabac.cpp
// Function: ymn::h264::picture_cabac::decode_residual_block(int*, ymn::h264::ctx_block_cat_e, int, unsigned char const*, int)
void picture_cabac::decode_residual_block(dctcoeff* block,
                                          const enum ctx_block_cat_e ctxBlockCat,
                                          const int idx,
                                          const uint8_t* scantable,
                                          const int max_coeff)
{
    /* Table 9-43 � Mapping of scanning position to ctxIdxInc for ctxBlockCat == 5, 9, or 13 */
    static const int significant_coeff_flag_offset_8x8[2][63] =
    {
        { 0, 1, 2, 3, 4, 5, 5, 4, 4, 3, 3, 4, 4, 4, 5, 5,
          4, 4, 4, 4, 3, 3, 6, 7, 7, 7, 8, 9,10, 9, 8, 7,
          7, 6,11,12,13,11, 6, 7, 8, 9,14,10, 9, 8, 6,11,
         12,13,11, 6, 9,14,10, 9,11,12,13,11,14,10,12 },
        { 0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 7, 7, 8, 4, 5,
          6, 9,10,10, 8,11,12,11, 9, 9,10,10, 8,11,12,11,
          9, 9,10,10, 8,11,12,11, 9, 9,10,10, 8,13,13, 9,
          9,10,10, 8,13,13, 9, 9,10,10,14,14,14,14,14 }
    };

    /* Table 9-43 � Mapping of scanning position to ctxIdxInc for ctxBlockCat == 5, 9, or 13 */
    static const int last_significant_coeff_flag_offset_8x8[63] =
    {
        0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
        3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
        5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8
    };

    int i;
    int index[64];
    int coeff_count = 0;
    const bool is_dc = (idx >= (16 * CC_MAX));

    if (max_coeff != 64) {
        for(i = 0; i < max_coeff - 1; ++i) {
            if (decode_significant_coeff_flag(ctxBlockCat, i)) {
                index[coeff_count++] = i;
                if (decode_last_significant_coeff_flag(ctxBlockCat, i))
                    i = max_coeff;
            }
        }
    }
    else {
        const bool is_field_mb = m_context_variables.mb_field_decoding_flag;
        for(i = 0; i < max_coeff - 1; ++i) {
            if (decode_significant_coeff_flag(ctxBlockCat, significant_coeff_flag_offset_8x8[is_field_mb][i])) {
                index[coeff_count++] = i;
                if (decode_last_significant_coeff_flag(ctxBlockCat, last_significant_coeff_flag_offset_8x8[i]))
                    i = max_coeff;
            }
        }
    }
    if (i == max_coeff - 1)
        index[coeff_count++] = i;

    if (is_dc) {
        mb_cache& nzc_cache = m_context_variables.non_zero_count_cache[idx - 16 * CC_MAX];
        nzc_cache[0] = coeff_count;
    }
    else {
        mb_cache& nzc_cache = m_context_variables.non_zero_count_cache[idx / 16];
        const int cache_idx = mb_cache_idx[idx % 16];
        if (max_coeff == 64)
            mb_cache_fill_rectangle_2x2(nzc_cache, cache_idx, coeff_count);
        else
            nzc_cache[cache_idx] = coeff_count;
    }

    /* If binIdx is equal to 0, ctxIdxInc is derived by
       ctxIdxInc = ((numDecodAbsLevelGt1 != 0) ? 0: Min(4, 1 + numDecodAbsLevelEq1)) */
    static const int coeff_abs_level_bin_idx_eq0[8] =
    {
        1, 2, 3, 4, 0, 0, 0, 0
    };

    /* Otherwise (binIdx is greater than 0), ctxIdxInc is derived by
       ctxIdxInc = 5 + Min(4 - ((ctxBlockCat == 3) ? 1 : 0), numDecodAbsLevelGt1) */
    static const int coeff_abs_level_bin_idx_gt0[2][8] =
    {
        /* ctxBlockCat == 3 */
        { 5, 5, 5, 5, 6, 7, 8, 8 },
        /* ctxBlockCat != 3 */
        { 5, 5, 5, 5, 6, 7, 8, 9 },
    };

    static const int coeff_abs_level_transition[2][8] =
    {
        /* update node ctx after decoding a coeff_abs_level == 1 */
        { 1, 2, 3, 3, 4, 5, 6, 7 },
        /* update node ctx after decoding a coeff_abs_level > 1 */
        { 4, 4, 4, 4, 5, 6, 7, 7 }
    };

    for (int node = 0; coeff_count > 0; ) {
        int ctxIdxInc;
        int coeff_abs_level;
        int pos = scantable[index[--coeff_count]];

        ctxIdxInc = coeff_abs_level_bin_idx_eq0[node];
        if (decode_coeff_abs_level_minus1(ctxBlockCat, ctxIdxInc) == 0) {
            coeff_abs_level = 1;
        }
        else {
            coeff_abs_level = 2;
            ctxIdxInc = coeff_abs_level_bin_idx_gt0[ctxBlockCat == 3 ? 0 : 1][node];
            while (coeff_abs_level < 15 && decode_coeff_abs_level_minus1(ctxBlockCat, ctxIdxInc))
                coeff_abs_level++;

#if 0
            if (coeff_abs_level >= 15) {
                int j = 0;
                while (m_cabac_decoder.decode_bypass())
                    j++;

                coeff_abs_level = 1;
                while (j--)
                    coeff_abs_level += coeff_abs_level + m_cabac_decoder.decode_bypass();

                coeff_abs_level += 14;
            }
#endif
        }

        block[pos] = (m_cabac_decoder.decode_bypass() == 0) ? coeff_abs_level : -coeff_abs_level;
        node = coeff_abs_level_transition[coeff_abs_level == 1 ? 0 : 1][node];
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x138, %rsp            # imm = 0x138
movq %r8, 0x28(%rsp)
movq %rcx, 0x18(%rsp)
movq %rsi, 0x20(%rsp)
movq %rdi, %r15
cmpl $0x40, %r9d
movl %edx, 0xc(%rsp)
movq %r9, (%rsp)
jne 0x17ad3
movzbl 0x19(%r15), %eax
leaq 0xdc0(%r15), %rbp
movl %edx, %r14d
xorl %r12d, %r12d
imulq $0xfc, %rax, %rax
leaq 0x6507(%rip), %rcx      # 0x1df50
addq %rax, %rcx
movq %rcx, 0x10(%rsp)
xorl %r13d, %r13d
movl %r12d, %ebx
movzbl 0x19(%r15), %eax
imulq $0x38, %rax, %rax
leaq 0x63c9(%rip), %rcx      # 0x1de30
addq %rcx, %rax
movl (%rax,%r14,4), %esi
movq 0x10(%rsp), %rax
addl (%rax,%rbx,4), %esi
movq %rbp, %rdi
callq 0x7d16
testl %eax, %eax
je 0x17ac0
movslq %r13d, %rax
movl %r12d, 0x30(%rsp,%rax,4)
movzbl 0x19(%r15), %eax
imulq $0x38, %rax, %rax
leaq 0x6406(%rip), %rcx      # 0x1dea0
addq %rcx, %rax
movl (%rax,%r14,4), %esi
leaq 0x66a8(%rip), %rax      # 0x1e150
addl (%rax,%rbx,4), %esi
movq %rbp, %rdi
callq 0x7d16
testl %eax, %eax
je 0x17abd
movl $0x40, %r12d
incl %r13d
leal 0x1(%r12), %ebx
cmpl $0x3e, %r12d
movl %ebx, %r12d
jl 0x17a54
jmp 0x17b5b
xorl %r13d, %r13d
movl $0x0, %ebx
cmpl $0x2, %r9d
jl 0x17b5b
movq (%rsp), %rax
leal -0x1(%rax), %r14d
leaq 0xdc0(%r15), %rbp
movl 0xc(%rsp), %r12d
xorl %ebx, %ebx
xorl %r13d, %r13d
movzbl 0x19(%r15), %eax
imulq $0x38, %rax, %rax
leaq 0x6326(%rip), %rcx      # 0x1de30
addq %rcx, %rax
movl (%rax,%r12,4), %esi
addl %ebx, %esi
movq %rbp, %rdi
callq 0x7d16
testl %eax, %eax
je 0x17b54
movslq %r13d, %rax
movl %ebx, 0x30(%rsp,%rax,4)
movzbl 0x19(%r15), %eax
imulq $0x38, %rax, %rax
leaq 0x636a(%rip), %rcx      # 0x1dea0
addq %rcx, %rax
movl (%rax,%r12,4), %esi
addl %ebx, %esi
movq %rbp, %rdi
callq 0x7d16
testl %eax, %eax
je 0x17b51
movq (%rsp), %rax
movl %eax, %ebx
incl %r13d
incl %ebx
cmpl %r14d, %ebx
jl 0x17afa
movq (%rsp), %rsi
leal -0x1(%rsi), %eax
cmpl %eax, %ebx
movq 0x18(%rsp), %rdi
jne 0x17b75
movslq %r13d, %rax
incl %r13d
movl %ebx, 0x30(%rsp,%rax,4)
leaq 0x80(%r15), %rax
cmpl $0x30, %edi
jl 0x17b8e
addl $-0x30, %edi
leaq (%rdi,%rdi,4), %rcx
movb %r13b, (%rax,%rcx,8)
jmp 0x17bd9
leal 0xf(%rdi), %ecx
testl %edi, %edi
cmovnsl %edi, %ecx
movl %ecx, %edx
andl $-0x10, %edx
subl %edx, %edi
sarl $0x4, %ecx
movslq %ecx, %rcx
leaq (%rcx,%rcx,4), %rcx
leaq (%rax,%rcx,8), %rax
movslq %edi, %rcx
leaq 0x622b(%rip), %rdx      # 0x1dde0
movzbl (%rcx,%rdx), %ecx
cmpl $0x40, %esi
jne 0x17bd5
movzbl %r13b, %edx
movl %r13d, %esi
shll $0x8, %esi
orl %edx, %esi
movw %si, (%rax,%rcx)
movw %si, 0x8(%rax,%rcx)
jmp 0x17bd9
movb %r13b, (%rax,%rcx)
testl %r13d, %r13d
jle 0x17cc9
addq $0xdc0, %r15            # imm = 0xDC0
movl 0xc(%rsp), %edx
movl %edx, %eax
leaq 0x631a(%rip), %rcx      # 0x1df10
movl (%rcx,%rax,4), %r12d
xorl %ecx, %ecx
cmpl $0x3, %edx
setne %cl
movl %r13d, %r13d
xorl %eax, %eax
shll $0x5, %ecx
leaq 0x663f(%rip), %rdx      # 0x1e250
addq %rcx, %rdx
movq %rdx, (%rsp)
movl %r12d, 0x10(%rsp)
movslq 0x2c(%rsp,%r13,4), %rcx
movq 0x28(%rsp), %rdx
movzbl (%rdx,%rcx), %ebx
movslq %eax, %r14
leaq 0x686b(%rip), %rax      # 0x1e4a0
movl (%rax,%r14,4), %esi
addl %r12d, %esi
movq %r15, %rdi
callq 0x7d16
testl %eax, %eax
je 0x17c78
movq (%rsp), %rax
movl (%rax,%r14,4), %ebp
addl %r12d, %ebp
movl $0x2, %r12d
movq %r15, %rdi
movl %ebp, %esi
callq 0x7d16
testl %eax, %eax
je 0x17c7e
incl %r12d
cmpl $0xf, %r12d
jne 0x17c59
movl $0xf, %r12d
jmp 0x17c7e
movl $0x1, %r12d
leaq -0x1(%r13), %rbp
movq %r15, %rdi
callq 0x7c68
movl %r12d, %ecx
negl %ecx
testl %eax, %eax
cmovel %r12d, %ecx
movq 0x20(%rsp), %rax
movl %ecx, (%rax,%rbx,4)
xorl %eax, %eax
cmpl $0x1, %r12d
setne %al
shll $0x5, %eax
leaq 0x65e0(%rip), %rcx      # 0x1e290
addq %rcx, %rax
movl (%rax,%r14,4), %eax
cmpq $0x1, %r13
movq %rbp, %r13
movl 0x10(%rsp), %r12d
jg 0x17c1d
addq $0x138, %rsp            # imm = 0x138
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop