// File: 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:
pushq %rbp
movq %rsp, %rbp
subq $0x60, %rsp
movl %edi, -0x4(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movl -0x4(%rbp), %eax
movl %eax, -0x24(%rbp)
movq -0x10(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x2c(%rbp)
movl -0x24(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x24(%rbp)
cmpl $0x0, %eax
jle 0x15b7
movq -0x10(%rbp), %rax
movslq -0x24(%rbp), %rcx
movl (%rax,%rcx,4), %eax
addl -0x2c(%rbp), %eax
movl %eax, -0x2c(%rbp)
jmp 0x1596
movl $0x3fffffff, %eax       # imm = 0x3FFFFFFF
xorl %edx, %edx
divl -0x2c(%rbp)
movl %eax, -0x28(%rbp)
movl -0x4(%rbp), %eax
movl %eax, -0x24(%rbp)
movl -0x24(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x24(%rbp)
cmpl $0x0, %eax
jl 0x1602
movq -0x10(%rbp), %rax
movslq -0x24(%rbp), %rcx
movl (%rax,%rcx,4), %edi
imull -0x28(%rbp), %edi
callq 0x17b0
movl %eax, %ecx
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
shll %cl, %edx
movq -0x20(%rbp), %rax
movslq -0x24(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
jmp 0x15ca
movq -0x18(%rbp), %rax
movl $0x0, (%rax)
movl $0x0, -0x34(%rbp)
movq -0x20(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x38(%rbp)
movl $0x1, -0x24(%rbp)
movl -0x24(%rbp), %eax
cmpl -0x4(%rbp), %eax
jge 0x1671
movq -0x20(%rbp), %rax
movslq -0x24(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x3c(%rbp)
movl -0x34(%rbp), %edx
movl -0x3c(%rbp), %eax
andl -0x38(%rbp), %eax
subl %eax, %edx
andl -0x3c(%rbp), %edx
movq -0x18(%rbp), %rax
movslq -0x24(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movq -0x18(%rbp), %rax
movslq -0x24(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x34(%rbp)
movl -0x3c(%rbp), %eax
movl %eax, -0x38(%rbp)
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0x1623
movl $0x0, -0x44(%rbp)
movl $0x0, -0x40(%rbp)
movl -0x4(%rbp), %eax
movl %eax, -0x24(%rbp)
movl -0x24(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x24(%rbp)
cmpl $0x0, %eax
jl 0x1747
movq -0x20(%rbp), %rax
movslq -0x24(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x4c(%rbp)
movq -0x18(%rbp), %rax
movslq -0x24(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x50(%rbp)
movl -0x40(%rbp), %eax
xorl $-0x1, %eax
orl -0x44(%rbp), %eax
movl -0x50(%rbp), %ecx
xorl $-0x1, %ecx
andl %ecx, %eax
andl -0x4c(%rbp), %eax
movl %eax, -0x44(%rbp)
movl -0x4c(%rbp), %eax
movl %eax, -0x40(%rbp)
movl -0x44(%rbp), %eax
movl %eax, -0x48(%rbp)
cmpl $0x0, -0x48(%rbp)
jge 0x16f6
movl -0x50(%rbp), %eax
shll %eax
movl %eax, -0x50(%rbp)
movl -0x48(%rbp), %eax
shll %eax
movl %eax, -0x48(%rbp)
movl -0x4c(%rbp), %eax
shll %eax
movl %eax, -0x4c(%rbp)
jmp 0x16d6
jmp 0x16f8
cmpl $0x0, -0x48(%rbp)
je 0x1726
movl -0x48(%rbp), %eax
subl $0x1, %eax
xorl -0x48(%rbp), %eax
andl -0x50(%rbp), %eax
addl -0x50(%rbp), %eax
movl %eax, -0x50(%rbp)
movl -0x48(%rbp), %eax
subl $0x1, %eax
andl -0x48(%rbp), %eax
movl %eax, -0x48(%rbp)
movl -0x4c(%rbp), %eax
shll %eax
movl %eax, -0x4c(%rbp)
jmp 0x16f8
movl -0x4c(%rbp), %edx
movq -0x20(%rbp), %rax
movslq -0x24(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movl -0x50(%rbp), %edx
movq -0x18(%rbp), %rax
movslq -0x24(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
jmp 0x1685
movl -0x4(%rbp), %eax
movl %eax, -0x24(%rbp)
movl -0x24(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x24(%rbp)
cmpl $0x0, %eax
jl 0x179d
movq -0x20(%rbp), %rax
movslq -0x24(%rbp), %rcx
movl (%rax,%rcx,4), %edi
callq 0x17e0
movl %eax, %ecx
movl %ecx, -0x30(%rbp)
movq -0x18(%rbp), %rax
movslq -0x24(%rbp), %rdx
movq %rdx, -0x58(%rbp)
movl (%rax,%rdx,4), %edx
shrl %cl, %edx
movq -0x58(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movl $0x20, %edx
subl -0x30(%rbp), %edx
movq -0x20(%rbp), %rax
movslq -0x24(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
jmp 0x174d
addq $0x60, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)