// File: tomfunkhouser[P]gaps/pkgs/jpeg/jchuff.c
// Function: jpeg_gen_optimal_table
GLOBAL(void)
jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])
{
#define MAX_CLEN 32		/* assumed maximum initial code length */
  UINT8 bits[MAX_CLEN+1];	/* bits[k] = # of symbols with code length k */
  int codesize[257];		/* codesize[k] = code length of symbol k */
  int others[257];		/* next symbol in current branch of tree */
  int c1, c2;
  int p, i, j;
  long v;

  /* This algorithm is explained in section K.2 of the JPEG standard */

  MEMZERO(bits, SIZEOF(bits));
  MEMZERO(codesize, SIZEOF(codesize));
  for (i = 0; i < 257; i++)
    others[i] = -1;		/* init links to empty */
  
  freq[256] = 1;		/* make sure 256 has a nonzero count */
  /* Including the pseudo-symbol 256 in the Huffman procedure guarantees
   * that no real symbol is given code-value of all ones, because 256
   * will be placed last in the largest codeword category.
   */

  /* Huffman's basic algorithm to assign optimal code lengths to symbols */

  for (;;) {
    /* Find the smallest nonzero frequency, set c1 = its symbol */
    /* In case of ties, take the larger symbol number */
    c1 = -1;
    v = 1000000000L;
    for (i = 0; i <= 256; i++) {
      if (freq[i] && freq[i] <= v) {
	v = freq[i];
	c1 = i;
      }
    }

    /* Find the next smallest nonzero frequency, set c2 = its symbol */
    /* In case of ties, take the larger symbol number */
    c2 = -1;
    v = 1000000000L;
    for (i = 0; i <= 256; i++) {
      if (freq[i] && freq[i] <= v && i != c1) {
	v = freq[i];
	c2 = i;
      }
    }

    /* Done if we've merged everything into one frequency */
    if (c2 < 0)
      break;
    
    /* Else merge the two counts/trees */
    freq[c1] += freq[c2];
    freq[c2] = 0;

    /* Increment the codesize of everything in c1's tree branch */
    codesize[c1]++;
    while (others[c1] >= 0) {
      c1 = others[c1];
      codesize[c1]++;
    }
    
    others[c1] = c2;		/* chain c2 onto c1's tree branch */
    
    /* Increment the codesize of everything in c2's tree branch */
    codesize[c2]++;
    while (others[c2] >= 0) {
      c2 = others[c2];
      codesize[c2]++;
    }
  }

  /* Now count the number of symbols of each code length */
  for (i = 0; i <= 256; i++) {
    if (codesize[i]) {
      /* The JPEG standard seems to think that this can't happen, */
      /* but I'm paranoid... */
      if (codesize[i] > MAX_CLEN)
	ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW);

      bits[codesize[i]]++;
    }
  }

  /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure
   * Huffman procedure assigned any such lengths, we must adjust the coding.
   * Here is what the JPEG spec says about how this next bit works:
   * Since symbols are paired for the longest Huffman code, the symbols are
   * removed from this length category two at a time.  The prefix for the pair
   * (which is one bit shorter) is allocated to one of the pair; then,
   * skipping the BITS entry for that prefix length, a code word from the next
   * shortest nonzero BITS entry is converted into a prefix for two code words
   * one bit longer.
   */
  
  for (i = MAX_CLEN; i > 16; i--) {
    while (bits[i] > 0) {
      j = i - 2;		/* find length of new prefix to be used */
      while (bits[j] == 0)
	j--;
      
      bits[i] -= 2;		/* remove two symbols */
      bits[i-1]++;		/* one goes in this length */
      bits[j+1] += 2;		/* two new symbols in this length */
      bits[j]--;		/* symbol of this length is now a prefix */
    }
  }

  /* Remove the count for the pseudo-symbol 256 from the largest codelength */
  while (bits[i] == 0)		/* find largest codelength still in use */
    i--;
  bits[i]--;
  
  /* Return final symbol counts (only for lengths 0..16) */
  MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits));
  
  /* Return a list of the symbols sorted by code length */
  /* It's not real clear to me why we don't need to consider the codelength
   * changes made above, but the JPEG spec seems to think this works.
   */
  p = 0;
  for (i = 1; i <= MAX_CLEN; i++) {
    for (j = 0; j <= 255; j++) {
      if (codesize[j] == i) {
	htbl->huffval[p] = (UINT8) j;
	p++;
      }
    }
  }

  /* Set sent_table FALSE so updated table will be written to JPEG file. */
  htbl->sent_table = FALSE;
}

// Assembly:
subq $0x888, %rsp            # imm = 0x888
movq %rdi, 0x880(%rsp)
movq %rsi, 0x878(%rsp)
movq %rdx, 0x870(%rsp)
leaq 0x840(%rsp), %rdi
xorl %esi, %esi
movl $0x21, %edx
callq 0xf280
leaq 0x430(%rsp), %rdi
xorl %esi, %esi
movl $0x404, %edx            # imm = 0x404
callq 0xf280
movl $0x0, 0x10(%rsp)
cmpl $0x101, 0x10(%rsp)      # imm = 0x101
jge 0xdd913
movslq 0x10(%rsp), %rax
movl $0xffffffff, 0x20(%rsp,%rax,4) # imm = 0xFFFFFFFF
movl 0x10(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x10(%rsp)
jmp 0xdd8ef
movq 0x870(%rsp), %rax
movq $0x1, 0x800(%rax)
movl $0xffffffff, 0x1c(%rsp) # imm = 0xFFFFFFFF
movq $0x3b9aca00, (%rsp)     # imm = 0x3B9ACA00
movl $0x0, 0x10(%rsp)
cmpl $0x100, 0x10(%rsp)      # imm = 0x100
jg 0xdd99f
movq 0x870(%rsp), %rax
movslq 0x10(%rsp), %rcx
cmpq $0x0, (%rax,%rcx,8)
je 0xdd990
movq 0x870(%rsp), %rax
movslq 0x10(%rsp), %rcx
movq (%rax,%rcx,8), %rax
cmpq (%rsp), %rax
jg 0xdd990
movq 0x870(%rsp), %rax
movslq 0x10(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, (%rsp)
movl 0x10(%rsp), %eax
movl %eax, 0x1c(%rsp)
jmp 0xdd992
movl 0x10(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x10(%rsp)
jmp 0xdd93e
movl $0xffffffff, 0x18(%rsp) # imm = 0xFFFFFFFF
movq $0x3b9aca00, (%rsp)     # imm = 0x3B9ACA00
movl $0x0, 0x10(%rsp)
cmpl $0x100, 0x10(%rsp)      # imm = 0x100
jg 0xdda22
movq 0x870(%rsp), %rax
movslq 0x10(%rsp), %rcx
cmpq $0x0, (%rax,%rcx,8)
je 0xdda13
movq 0x870(%rsp), %rax
movslq 0x10(%rsp), %rcx
movq (%rax,%rcx,8), %rax
cmpq (%rsp), %rax
jg 0xdda13
movl 0x10(%rsp), %eax
cmpl 0x1c(%rsp), %eax
je 0xdda13
movq 0x870(%rsp), %rax
movslq 0x10(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, (%rsp)
movl 0x10(%rsp), %eax
movl %eax, 0x18(%rsp)
jmp 0xdda15
movl 0x10(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x10(%rsp)
jmp 0xdd9b7
cmpl $0x0, 0x18(%rsp)
jge 0xdda2e
jmp 0xddb09
movq 0x870(%rsp), %rax
movslq 0x18(%rsp), %rcx
movq (%rax,%rcx,8), %rdx
movq 0x870(%rsp), %rax
movslq 0x1c(%rsp), %rcx
addq (%rax,%rcx,8), %rdx
movq %rdx, (%rax,%rcx,8)
movq 0x870(%rsp), %rax
movslq 0x18(%rsp), %rcx
movq $0x0, (%rax,%rcx,8)
movslq 0x1c(%rsp), %rax
movl 0x430(%rsp,%rax,4), %ecx
addl $0x1, %ecx
movl %ecx, 0x430(%rsp,%rax,4)
movslq 0x1c(%rsp), %rax
cmpl $0x0, 0x20(%rsp,%rax,4)
jl 0xddab0
movslq 0x1c(%rsp), %rax
movl 0x20(%rsp,%rax,4), %eax
movl %eax, 0x1c(%rsp)
movslq 0x1c(%rsp), %rax
movl 0x430(%rsp,%rax,4), %ecx
addl $0x1, %ecx
movl %ecx, 0x430(%rsp,%rax,4)
jmp 0xdda7f
movl 0x18(%rsp), %ecx
movslq 0x1c(%rsp), %rax
movl %ecx, 0x20(%rsp,%rax,4)
movslq 0x18(%rsp), %rax
movl 0x430(%rsp,%rax,4), %ecx
addl $0x1, %ecx
movl %ecx, 0x430(%rsp,%rax,4)
movslq 0x18(%rsp), %rax
cmpl $0x0, 0x20(%rsp,%rax,4)
jl 0xddb04
movslq 0x18(%rsp), %rax
movl 0x20(%rsp,%rax,4), %eax
movl %eax, 0x18(%rsp)
movslq 0x18(%rsp), %rax
movl 0x430(%rsp,%rax,4), %ecx
addl $0x1, %ecx
movl %ecx, 0x430(%rsp,%rax,4)
jmp 0xddad3
jmp 0xdd926
movl $0x0, 0x10(%rsp)
cmpl $0x100, 0x10(%rsp)      # imm = 0x100
jg 0xddb90
movslq 0x10(%rsp), %rax
cmpl $0x0, 0x430(%rsp,%rax,4)
je 0xddb81
movslq 0x10(%rsp), %rax
cmpl $0x20, 0x430(%rsp,%rax,4)
jle 0xddb63
movq 0x880(%rsp), %rax
movq (%rax), %rax
movl $0x27, 0x28(%rax)
movq 0x880(%rsp), %rax
movq (%rax), %rax
movq (%rax), %rax
movq 0x880(%rsp), %rdi
callq *%rax
movslq 0x10(%rsp), %rax
movslq 0x430(%rsp,%rax,4), %rax
movb 0x840(%rsp,%rax), %cl
addb $0x1, %cl
movb %cl, 0x840(%rsp,%rax)
jmp 0xddb83
movl 0x10(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x10(%rsp)
jmp 0xddb11
movl $0x20, 0x10(%rsp)
cmpl $0x10, 0x10(%rsp)
jle 0xddc5e
jmp 0xddba5
movslq 0x10(%rsp), %rax
movzbl 0x840(%rsp,%rax), %eax
cmpl $0x0, %eax
jle 0xddc4c
movl 0x10(%rsp), %eax
subl $0x2, %eax
movl %eax, 0xc(%rsp)
movslq 0xc(%rsp), %rax
movzbl 0x840(%rsp,%rax), %eax
cmpl $0x0, %eax
jne 0xddbe5
movl 0xc(%rsp), %eax
addl $-0x1, %eax
movl %eax, 0xc(%rsp)
jmp 0xddbc6
movslq 0x10(%rsp), %rax
movzbl 0x840(%rsp,%rax), %ecx
subl $0x2, %ecx
movb %cl, 0x840(%rsp,%rax)
movl 0x10(%rsp), %eax
subl $0x1, %eax
cltq
movb 0x840(%rsp,%rax), %cl
addb $0x1, %cl
movb %cl, 0x840(%rsp,%rax)
movl 0xc(%rsp), %eax
addl $0x1, %eax
cltq
movzbl 0x840(%rsp,%rax), %ecx
addl $0x2, %ecx
movb %cl, 0x840(%rsp,%rax)
movslq 0xc(%rsp), %rax
movb 0x840(%rsp,%rax), %cl
addb $-0x1, %cl
movb %cl, 0x840(%rsp,%rax)
jmp 0xddba5
jmp 0xddc4e
movl 0x10(%rsp), %eax
addl $-0x1, %eax
movl %eax, 0x10(%rsp)
jmp 0xddb98
jmp 0xddc60
movslq 0x10(%rsp), %rax
movzbl 0x840(%rsp,%rax), %eax
cmpl $0x0, %eax
jne 0xddc7f
movl 0x10(%rsp), %eax
addl $-0x1, %eax
movl %eax, 0x10(%rsp)
jmp 0xddc60
movslq 0x10(%rsp), %rax
movb 0x840(%rsp,%rax), %cl
addb $-0x1, %cl
movb %cl, 0x840(%rsp,%rax)
movq 0x878(%rsp), %rax
movq 0x840(%rsp), %rcx
movq %rcx, (%rax)
movq 0x848(%rsp), %rcx
movq %rcx, 0x8(%rax)
movb 0x850(%rsp), %cl
movb %cl, 0x10(%rax)
movl $0x0, 0x14(%rsp)
movl $0x1, 0x10(%rsp)
cmpl $0x20, 0x10(%rsp)
jg 0xddd39
movl $0x0, 0xc(%rsp)
cmpl $0xff, 0xc(%rsp)
jg 0xddd2a
movslq 0xc(%rsp), %rax
movl 0x430(%rsp,%rax,4), %eax
cmpl 0x10(%rsp), %eax
jne 0xddd1b
movl 0xc(%rsp), %eax
movb %al, %dl
movq 0x878(%rsp), %rax
movslq 0x14(%rsp), %rcx
movb %dl, 0x11(%rax,%rcx)
movl 0x14(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x14(%rsp)
jmp 0xddd1d
movl 0xc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xc(%rsp)
jmp 0xddcdd
jmp 0xddd2c
movl 0x10(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x10(%rsp)
jmp 0xddcce
movq 0x878(%rsp), %rax
movl $0x0, 0x114(%rax)
addq $0x888, %rsp            # imm = 0x888
retq
nopw %cs:(%rax,%rax)