// File: /workspace/github_cpp_makefile_star2_O2/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, 0x10(%rsp)
movl %edx, %ebp
movq %rsi, 0x20(%rsp)
movq %rdi, %r15
cmpl $0x40, %r9d
movq %r9, 0x8(%rsp)
jne 0x12aea
movzbl 0x19(%r15), %eax
xorl %ebx, %ebx
imulq $0xfc, %rax, %rax
leaq 0x6527(%rip), %r14      # 0x18fc0
addq %rax, %r14
xorl %r13d, %r13d
cmpl $0x3e, %r13d
jg 0x12b31
movl %r13d, %r12d
movl (%r14,%r12,4), %edx
movq %r15, %rdi
movl %ebp, %esi
callq 0x129ee
testl %eax, %eax
je 0x12ae5
movslq %ebx, %rax
movl %r13d, 0x30(%rsp,%rax,4)
leaq 0x66f3(%rip), %rax      # 0x191c0
movl (%rax,%r12,4), %edx
movq %r15, %rdi
movl %ebp, %esi
callq 0x12a14
testl %eax, %eax
je 0x12ae3
pushq $0x40
popq %r13
incl %ebx
incl %r13d
jmp 0x12a9f
leal -0x1(%r9), %r14d
xorl %ebx, %ebx
xorl %r13d, %r13d
cmpl %r14d, %r13d
jge 0x12b3a
movq %r15, %rdi
movl %ebp, %esi
movl %r13d, %edx
callq 0x129ee
testl %eax, %eax
je 0x12b2c
movslq %ebx, %rax
movl %r13d, 0x30(%rsp,%rax,4)
movq %r15, %rdi
movl %ebp, %esi
movl %r13d, %edx
callq 0x12a14
testl %eax, %eax
je 0x12b2a
movq 0x8(%rsp), %rax
movl %eax, %r13d
incl %ebx
incl %r13d
jmp 0x12af3
movq 0x8(%rsp), %rax
leal -0x1(%rax), %r14d
cmpl %r14d, %r13d
jne 0x12b49
movslq %ebx, %rax
incl %ebx
movl %r14d, 0x30(%rsp,%rax,4)
leaq 0x80(%r15), %rcx
movq 0x10(%rsp), %rax
cmpl $0x30, %eax
jl 0x12b63
addl $-0x30, %eax
imulq $0x28, %rax, %rax
jmp 0x12b9b
pushq $0x10
popq %rsi
cltd
idivl %esi
cltq
imulq $0x28, %rax, %rax
addq %rax, %rcx
movslq %edx, %rax
leaq 0x62d4(%rip), %rdx      # 0x18e50
movzbl (%rax,%rdx), %eax
cmpl $0x40, 0x8(%rsp)
jne 0x12b9b
movzbl %bl, %edx
imull $0x101, %edx, %edx      # imm = 0x101
movw %dx, (%rcx,%rax)
movw %dx, 0x8(%rcx,%rax)
jmp 0x12b9e
movb %bl, (%rcx,%rax)
xorl %ecx, %ecx
cmpl $0x3, %ebp
setne %cl
leaq 0xdc0(%r15), %rax
movq %rax, 0x10(%rsp)
movl %ebx, %ebx
xorl %eax, %eax
shll $0x5, %ecx
leaq 0x6700(%rip), %rdx      # 0x192c0
addq %rcx, %rdx
movq %rdx, 0x18(%rsp)
testl %ebx, %ebx
jle 0x12c76
movslq 0x2c(%rsp,%rbx,4), %rcx
movq 0x28(%rsp), %rdx
movzbl (%rdx,%rcx), %r13d
movslq %eax, %r14
leaq 0x6927(%rip), %rax      # 0x19510
movl (%rax,%r14,4), %edx
movq %r15, %rdi
movl %ebp, %esi
callq 0x12a3a
pushq $0x1
popq %r12
testl %eax, %eax
je 0x12c36
movq %r13, 0x8(%rsp)
movq 0x18(%rsp), %rax
movl (%rax,%r14,4), %r13d
pushq $0x2
popq %r12
cmpl $0xf, %r12d
je 0x12c2d
movq %r15, %rdi
movl %ebp, %esi
movl %r13d, %edx
callq 0x12a3a
testl %eax, %eax
je 0x12c31
incl %r12d
jmp 0x12c11
pushq $0xf
popq %r12
movq 0x8(%rsp), %r13
decq %rbx
movq 0x10(%rsp), %rdi
callq 0x6a14
movl %r12d, %ecx
negl %ecx
testl %eax, %eax
cmovel %r12d, %ecx
movq 0x20(%rsp), %rax
movl %ecx, (%rax,%r13,4)
xorl %eax, %eax
cmpl $0x1, %r12d
setne %al
shll $0x5, %eax
leaq 0x6696(%rip), %rcx      # 0x19300
addq %rcx, %rax
movl (%rax,%r14,4), %eax
jmp 0x12bc8
addq $0x138, %rsp            # imm = 0x138
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq