// File: sbingner[P]kerneldec/lzfse/src/lzfse_fse.c
// Function: fse_init_value_decoder_table
void fse_init_value_decoder_table(int nstates, int nsymbols,
                                  const uint16_t *__restrict freq,
                                  const uint8_t *__restrict symbol_vbits,
                                  const int32_t *__restrict symbol_vbase,
                                  fse_value_decoder_entry *__restrict t) {
  assert(nsymbols <= 256);
  assert(fse_check_freq(freq, nsymbols, nstates) == 0);

  int n_clz = __builtin_clz(nstates);
  for (int i = 0; i < nsymbols; i++) {
    int f = (int)freq[i];
    if (f == 0)
      continue; // skip this symbol, no occurrences

    int k =
        __builtin_clz(f) - n_clz; // shift needed to ensure N <= (F<<K) < 2*N
    int j0 = ((2 * nstates) >> k) - f;

    fse_value_decoder_entry ei = {0};
    ei.value_bits = symbol_vbits[i];
    ei.vbase = symbol_vbase[i];

    // Initialize all states S reached by this symbol: OFFSET <= S < OFFSET + F
    for (int j = 0; j < f; j++) {
      fse_value_decoder_entry e = ei;

      if (j < j0) {
        e.total_bits = (uint8_t)k + e.value_bits;
        e.delta = (int16_t)(((f + j) << k) - nstates);
      } else {
        e.total_bits = (uint8_t)(k - 1) + e.value_bits;
        e.delta = (int16_t)((j - j0) << (k - 1));
      }

      memcpy(t, &e, 8);
      t++;
    }
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x80, %rsp
movl %edi, -0x28(%rbp)
movl %esi, -0x2c(%rbp)
movq %rdx, -0x38(%rbp)
movq %rcx, -0x40(%rbp)
movq %r8, -0x48(%rbp)
movq %r9, -0x50(%rbp)
cmpl $0x100, -0x2c(%rbp)     # imm = 0x100
jg 0xddcc
jmp 0xddeb
leaq 0x2d15(%rip), %rdi      # 0x10ae8
leaq 0x2d1e(%rip), %rsi      # 0x10af8
movl $0x72, %edx
leaq 0x2da1(%rip), %rcx      # 0x10b87
callq 0x3070
movq -0x38(%rbp), %rdx
movslq -0x2c(%rbp), %rcx
movslq -0x28(%rbp), %rax
movq %rdx, -0x8(%rbp)
movq %rcx, -0x10(%rbp)
movq %rax, -0x18(%rbp)
movq $0x0, -0x20(%rbp)
movl $0x0, -0x24(%rbp)
movslq -0x24(%rbp), %rax
cmpq -0x10(%rbp), %rax
jae 0xde3b
movq -0x8(%rbp), %rax
movslq -0x24(%rbp), %rcx
movzwl (%rax,%rcx,2), %eax
addq -0x20(%rbp), %rax
movq %rax, -0x20(%rbp)
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0xde12
movq -0x20(%rbp), %rdx
movq -0x18(%rbp), %rsi
xorl %eax, %eax
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
cmpq %rsi, %rdx
cmoval %ecx, %eax
cmpl $0x0, %eax
jne 0xde57
jmp 0xde76
leaq 0x2cfc(%rip), %rdi      # 0x10b5a
leaq 0x2c93(%rip), %rsi      # 0x10af8
movl $0x73, %edx
leaq 0x2d16(%rip), %rcx      # 0x10b87
callq 0x3070
movl -0x28(%rbp), %eax
bsrl %eax, %eax
xorl $0x1f, %eax
movl %eax, -0x54(%rbp)
movl $0x0, -0x58(%rbp)
movl -0x58(%rbp), %eax
cmpl -0x2c(%rbp), %eax
jge 0xdf95
movq -0x38(%rbp), %rax
movslq -0x58(%rbp), %rcx
movzwl (%rax,%rcx,2), %eax
movl %eax, -0x5c(%rbp)
cmpl $0x0, -0x5c(%rbp)
jne 0xdeaf
jmp 0xdf87
movl -0x5c(%rbp), %eax
bsrl %eax, %eax
xorl $0x1f, %eax
subl -0x54(%rbp), %eax
movl %eax, -0x60(%rbp)
movl -0x28(%rbp), %eax
shll %eax
movl -0x60(%rbp), %ecx
sarl %cl, %eax
subl -0x5c(%rbp), %eax
movl %eax, -0x64(%rbp)
leaq -0x6c(%rbp), %rdi
xorl %esi, %esi
movl $0x8, %edx
callq 0x3080
movq -0x40(%rbp), %rax
movslq -0x58(%rbp), %rcx
movb (%rax,%rcx), %al
movb %al, -0x6b(%rbp)
movq -0x48(%rbp), %rax
movslq -0x58(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x68(%rbp)
movl $0x0, -0x70(%rbp)
movl -0x70(%rbp), %eax
cmpl -0x5c(%rbp), %eax
jge 0xdf85
movq -0x6c(%rbp), %rax
movq %rax, -0x78(%rbp)
movl -0x70(%rbp), %eax
cmpl -0x64(%rbp), %eax
jge 0xdf3c
movl -0x60(%rbp), %eax
movzbl %al, %eax
movzbl -0x77(%rbp), %ecx
addl %ecx, %eax
movb %al, -0x78(%rbp)
movl -0x5c(%rbp), %eax
addl -0x70(%rbp), %eax
movl -0x60(%rbp), %ecx
shll %cl, %eax
subl -0x28(%rbp), %eax
movw %ax, -0x76(%rbp)
jmp 0xdf60
movl -0x60(%rbp), %eax
subl $0x1, %eax
movzbl %al, %eax
movzbl -0x77(%rbp), %ecx
addl %ecx, %eax
movb %al, -0x78(%rbp)
movl -0x70(%rbp), %eax
subl -0x64(%rbp), %eax
movl -0x60(%rbp), %ecx
subl $0x1, %ecx
shll %cl, %eax
movw %ax, -0x76(%rbp)
movq -0x50(%rbp), %rax
movq -0x78(%rbp), %rcx
movq %rcx, (%rax)
movq -0x50(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x50(%rbp)
movl -0x70(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x70(%rbp)
jmp 0xdf01
jmp 0xdf87
movl -0x58(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x58(%rbp)
jmp 0xde89
addq $0x80, %rsp
popq %rbp
retq
nop