// File: sbingner[P]kerneldec/lzfse/src/lzfse_fse.c
// Function: fse_normalize_freq
void fse_normalize_freq(int nstates, int nsymbols, const uint32_t *__restrict t,
                        uint16_t *__restrict freq) {
  uint32_t s_count = 0;
  int remaining = nstates; // must be signed; this may become < 0
  int max_freq = 0;
  int max_freq_sym = 0;
  int shift = __builtin_clz(nstates) - 1;
  uint32_t highprec_step;

  // Compute the total number of symbol occurrences
  for (int i = 0; i < nsymbols; i++)
    s_count += t[i];

  if (s_count == 0)
    highprec_step = 0; // no symbols used
  else
    highprec_step = ((uint32_t)1 << 31) / s_count;

  for (int i = 0; i < nsymbols; i++) {

    // Rescale the occurrence count to get the normalized frequency.
    // Round up if the fractional part is >= 0.5; otherwise round down.
    // For efficiency, we do this calculation using integer arithmetic.
    int f = (((t[i] * highprec_step) >> shift) + 1) >> 1;

    // If a symbol was used, it must be given a nonzero normalized frequency.
    if (f == 0 && t[i] != 0)
      f = 1;

    freq[i] = f;
    remaining -= f;

    // Remember the maximum frequency and which symbol had it.
    if (f > max_freq) {
      max_freq = f;
      max_freq_sym = i;
    }
  }

  // If there remain states to be assigned, then just assign them to the most
  // frequent symbol.  Alternatively, if we assigned more states than were
  // actually available, then either remove states from the most frequent symbol
  // (for minor overruns) or use the slower adjustment algorithm (for major
  // overruns).
  if (-remaining < (max_freq >> 2)) {
    freq[max_freq_sym] += remaining;
  } else {
    fse_adjust_freqs(freq, -remaining, nsymbols);
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x40, %rsp
movl %edi, -0x4(%rbp)
movl %esi, -0x8(%rbp)
movq %rdx, -0x10(%rbp)
movq %rcx, -0x18(%rbp)
movl $0x0, -0x1c(%rbp)
movl -0x4(%rbp), %eax
movl %eax, -0x20(%rbp)
movl $0x0, -0x24(%rbp)
movl $0x0, -0x28(%rbp)
movl -0x4(%rbp), %eax
bsrl %eax, %eax
xorl $0x1f, %eax
subl $0x1, %eax
movl %eax, -0x2c(%rbp)
movl $0x0, -0x34(%rbp)
movl -0x34(%rbp), %eax
cmpl -0x8(%rbp), %eax
jge 0xe00b
movq -0x10(%rbp), %rax
movslq -0x34(%rbp), %rcx
movl (%rax,%rcx,4), %eax
addl -0x1c(%rbp), %eax
movl %eax, -0x1c(%rbp)
movl -0x34(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x34(%rbp)
jmp 0xdfe7
cmpl $0x0, -0x1c(%rbp)
jne 0xe01a
movl $0x0, -0x30(%rbp)
jmp 0xe027
movl $0x80000000, %eax       # imm = 0x80000000
xorl %edx, %edx
divl -0x1c(%rbp)
movl %eax, -0x30(%rbp)
movl $0x0, -0x38(%rbp)
movl -0x38(%rbp), %eax
cmpl -0x8(%rbp), %eax
jge 0xe0ab
movq -0x10(%rbp), %rax
movslq -0x38(%rbp), %rcx
movl (%rax,%rcx,4), %eax
imull -0x30(%rbp), %eax
movl -0x2c(%rbp), %ecx
shrl %cl, %eax
addl $0x1, %eax
shrl %eax
movl %eax, -0x3c(%rbp)
cmpl $0x0, -0x3c(%rbp)
jne 0xe06d
movq -0x10(%rbp), %rax
movslq -0x38(%rbp), %rcx
cmpl $0x0, (%rax,%rcx,4)
je 0xe06d
movl $0x1, -0x3c(%rbp)
movl -0x3c(%rbp), %eax
movw %ax, %dx
movq -0x18(%rbp), %rax
movslq -0x38(%rbp), %rcx
movw %dx, (%rax,%rcx,2)
movl -0x3c(%rbp), %ecx
movl -0x20(%rbp), %eax
subl %ecx, %eax
movl %eax, -0x20(%rbp)
movl -0x3c(%rbp), %eax
cmpl -0x24(%rbp), %eax
jle 0xe09e
movl -0x3c(%rbp), %eax
movl %eax, -0x24(%rbp)
movl -0x38(%rbp), %eax
movl %eax, -0x28(%rbp)
jmp 0xe0a0
movl -0x38(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x38(%rbp)
jmp 0xe02e
xorl %eax, %eax
subl -0x20(%rbp), %eax
movl -0x24(%rbp), %ecx
sarl $0x2, %ecx
cmpl %ecx, %eax
jge 0xe0d1
movl -0x20(%rbp), %esi
movq -0x18(%rbp), %rax
movslq -0x28(%rbp), %rcx
movzwl (%rax,%rcx,2), %edx
addl %esi, %edx
movw %dx, (%rax,%rcx,2)
jmp 0xe0e2
movq -0x18(%rbp), %rdi
xorl %esi, %esi
subl -0x20(%rbp), %esi
movl -0x8(%rbp), %edx
callq 0xe0f0
addq $0x40, %rsp
popq %rbp
retq
nopl (%rax,%rax)