// File: /workspace/github_cpp_makefile_star2_O2/ctSkennerton[P]fxtract/util/ordhuff.c
// Function: ordhuff
void
ordhuff( 
    int             ncodes,        // length of (all) vectors.
    unsigned const  vFreq[], 
    unsigned        vCode[],
    unsigned        vBits[])
{
    int             i;
    unsigned        scale, sum, z;
    unsigned        prevcode, prevbits, currbits, prevmask, comb;

    for (i = ncodes, sum = vFreq[0]; --i > 0;) sum += vFreq[i];

    /* Calculate initial code widths, as left-justified bitmasks;
     *   e.g 0xF8000000 for a code with length "5".
     * NOTE: 0x7FFFFFFF as a quotient can cause overflows,
     *   i.e. vCode[i] < vCode[i-1].
     */
    scale   = 0x3FFFFFFF / sum;
        //XXX: use a nonlinear scaling
    for (i = ncodes; --i >= 0;)
	vBits[i] = -1 << fls(vFreq[i] * scale);

    /* Calculate initial code values, also left-justified.
     * gcc has a bit of trouble optimizing induction values here.
     */
    prevcode = vCode[0] = 0;
    prevbits = vBits[0];

    for (i = 1; i < ncodes; ++i) {
        currbits = vBits[i];
        vCode[i] = (prevcode - (currbits & prevbits)) & currbits;
        prevcode = vCode[i];
        prevbits = currbits;
    }

    /* Comb out unnecessary bits, equivalent to tree nodes with
     * one child. A bit is combed out, if it is a zero bit in 
     * the current code, and it was either an unnecessary bit 
     * in the previous code, or not part of the previous code 
     * (below the masked bits).
     */
    prevmask = comb = 0;
    for (i = ncodes; --i >= 0;) {
        int             x;  // signed for easy high-bit test
        unsigned        currmask = vBits[i], currcode = vCode[i];

        comb = (~prevmask | comb) & ~currcode & currmask;
        prevmask = currmask;

        // Squeeze out leading useless bits in a tiny loop:
        for (x = comb; x < 0; x <<= 1, currmask <<= 1)
            currcode <<= 1;

        // Squeeze out remaining combed bits in a larger loop:
        for (; x; x &= x - 1, currmask <<= 1)
            currcode += ((x - 1) ^ x) & currcode;

        vBits[i] = currmask, vCode[i] = currcode;
    }

    /* Convert left-justified codes and corresponding bitmasks
     *  to right-justified codes and corresponding lengths.
     * OTOH: probably more useful to leave codes left-justified
     *	and use an int64_t shifter (e.g SHLD %cl, %edx, %eax)
     */
    for (i = ncodes; --i >= 0;) {
        vCode[i] >>= z = bsrl(vBits[i]);
        vBits[i] = 32 - z;
    }
}

// Assembly:
movq %rcx, %r8
movq %rdx, %r9
movl (%rsi), %ecx
movl %edi, %r10d
movq %r10, %rax
cmpl $0x2, %eax
jl 0x143c
addl -0x4(%rsi,%rax,4), %ecx
decq %rax
jmp 0x142e
pushq %rbp
pushq %rbx
movl $0x3fffffff, %eax       # imm = 0x3FFFFFFF
xorl %edx, %edx
divl %ecx
movl %eax, %edx
movl $0xffffffff, %r11d      # imm = 0xFFFFFFFF
movq %r10, %rbx
testl %ebx, %ebx
jle 0x147b
movl -0x4(%rsi,%rbx,4), %eax
imull %edx, %eax
testl %eax, %eax
je 0x146a
bsrl %eax, %eax
movl %eax, %ecx
incl %ecx
jmp 0x146c
xorl %ecx, %ecx
movl %r11d, %eax
shll %cl, %eax
movl %eax, -0x4(%r8,%rbx,4)
decq %rbx
jmp 0x1452
andl $0x0, (%r9)
movl (%r8), %esi
movslq %edi, %rax
xorl %ecx, %ecx
movabsq $0x1, %rdx
cmpq %rax, %rdx
jge 0x14ab
movl (%r8,%rdx,4), %edi
andl %edi, %esi
subl %esi, %ecx
andl %edi, %ecx
movl %ecx, (%r9,%rdx,4)
incq %rdx
movl %edi, %esi
jmp 0x1491
xorl %edi, %edi
movq %r10, %rax
xorl %ecx, %ecx
testl %eax, %eax
jle 0x1506
decq %rax
movl (%r8,%rax,4), %edx
movl (%r9,%rax,4), %esi
notl %edi
orl %edi, %ecx
movl %esi, %edi
notl %edi
andl %edx, %ecx
andl %edi, %ecx
movl %ecx, %r11d
movl %edx, %edi
testl %r11d, %r11d
jns 0x14f5
addl %esi, %esi
addl %r11d, %r11d
addl %edi, %edi
jmp 0x14d2
leal -0x1(%r11), %ebx
movl %ebx, %ebp
xorl %r11d, %ebp
andl %esi, %ebp
addl %ebp, %esi
andl %r11d, %ebx
addl %edi, %edi
movl %ebx, %r11d
testl %r11d, %r11d
jne 0x14e0
movl %edi, (%r8,%rax,4)
movl %esi, (%r9,%rax,4)
movl %edx, %edi
jmp 0x14b2
movl $0x20, %eax
popq %rbx
popq %rbp
testl %r10d, %r10d
jle 0x152d
movl -0x4(%r8,%r10,4), %ecx
bsrl %ecx, %ecx
shrl %cl, -0x4(%r9,%r10,4)
movl %eax, %edx
subl %ecx, %edx
movl %edx, -0x4(%r8,%r10,4)
decq %r10
jmp 0x150d
retq
nop