// File: sbingner[P]kerneldec/lzfse/src/lzfse_decode_base.c
// Function: lzfse_decode_v1
static inline int lzfse_decode_v1(lzfse_compressed_block_header_v1 *out,
                                const lzfse_compressed_block_header_v2 *in) {
  // Clear all fields
  memset(out, 0x00, sizeof(lzfse_compressed_block_header_v1));

  uint64_t v0 = in->packed_fields[0];
  uint64_t v1 = in->packed_fields[1];
  uint64_t v2 = in->packed_fields[2];

  out->magic = LZFSE_COMPRESSEDV1_BLOCK_MAGIC;
  out->n_raw_bytes = in->n_raw_bytes;

  // Literal state
  out->n_literals = get_field(v0, 0, 20);
  out->n_literal_payload_bytes = get_field(v0, 20, 20);
  out->literal_bits = (int)get_field(v0, 60, 3) - 7;
  out->literal_state[0] = get_field(v1, 0, 10);
  out->literal_state[1] = get_field(v1, 10, 10);
  out->literal_state[2] = get_field(v1, 20, 10);
  out->literal_state[3] = get_field(v1, 30, 10);

  // L,M,D state
  out->n_matches = get_field(v0, 40, 20);
  out->n_lmd_payload_bytes = get_field(v1, 40, 20);
  out->lmd_bits = (int)get_field(v1, 60, 3) - 7;
  out->l_state = get_field(v2, 32, 10);
  out->m_state = get_field(v2, 42, 10);
  out->d_state = get_field(v2, 52, 10);

  // Total payload size
  out->n_payload_bytes =
      out->n_literal_payload_bytes + out->n_lmd_payload_bytes;

  // Freq tables
  uint16_t *dst = &(out->l_freq[0]);
  const uint8_t *src = &(in->freq[0]);
  const uint8_t *src_end =
      (const uint8_t *)in + get_field(v2, 0, 32); // first byte after header
  uint32_t accum = 0;
  int accum_nbits = 0;

  // No freq tables?
  if (src_end == src)
    return 0; // OK, freq tables were omitted

  for (int i = 0; i < LZFSE_ENCODE_L_SYMBOLS + LZFSE_ENCODE_M_SYMBOLS +
                          LZFSE_ENCODE_D_SYMBOLS + LZFSE_ENCODE_LITERAL_SYMBOLS;
       i++) {
    // Refill accum, one byte at a time, until we reach end of header, or accum
    // is full
    while (src < src_end && accum_nbits + 8 <= 32) {
      accum |= (uint32_t)(*src) << accum_nbits;
      accum_nbits += 8;
      src++;
    }

    // Decode and store value
    int nbits = 0;
    dst[i] = lzfse_decode_v1_freq_value(accum, &nbits);

    if (nbits > accum_nbits)
      return -1; // failed

    // Consume nbits bits
    accum >>= nbits;
    accum_nbits -= nbits;
  }

  if (accum_nbits >= 8 || src != src_end)
    return -1; // we need to end up exactly at the end of header, with less than
               // 8 bits in accumulator

  return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x70, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq -0x10(%rbp), %rdi
xorl %esi, %esi
movl $0x304, %edx            # imm = 0x304
callq 0x3080
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x20(%rbp)
movq -0x18(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x28(%rbp)
movq -0x18(%rbp), %rax
movq 0x18(%rax), %rax
movq %rax, -0x30(%rbp)
movq -0x10(%rbp), %rax
movl $0x31787662, (%rax)     # imm = 0x31787662
movq -0x18(%rbp), %rax
movl 0x4(%rax), %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0x4(%rax)
movq -0x20(%rbp), %rdi
xorl %esi, %esi
movl $0x14, %edx
callq 0xa460
movl %eax, %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0xc(%rax)
movq -0x20(%rbp), %rdi
movl $0x14, %edx
movl %edx, %esi
callq 0xa460
movl %eax, %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0x14(%rax)
movq -0x20(%rbp), %rdi
movl $0x3c, %esi
movl $0x3, %edx
callq 0xa460
movl %eax, %ecx
subl $0x7, %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0x1c(%rax)
movq -0x28(%rbp), %rdi
xorl %esi, %esi
movl $0xa, %edx
callq 0xa460
movw %ax, %cx
movq -0x10(%rbp), %rax
movw %cx, 0x20(%rax)
movq -0x28(%rbp), %rdi
movl $0xa, %edx
movl %edx, %esi
callq 0xa460
movw %ax, %cx
movq -0x10(%rbp), %rax
movw %cx, 0x22(%rax)
movq -0x28(%rbp), %rdi
movl $0x14, %esi
movl $0xa, %edx
callq 0xa460
movw %ax, %cx
movq -0x10(%rbp), %rax
movw %cx, 0x24(%rax)
movq -0x28(%rbp), %rdi
movl $0x1e, %esi
movl $0xa, %edx
callq 0xa460
movw %ax, %cx
movq -0x10(%rbp), %rax
movw %cx, 0x26(%rax)
movq -0x20(%rbp), %rdi
movl $0x28, %esi
movl $0x14, %edx
callq 0xa460
movl %eax, %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0x10(%rax)
movq -0x28(%rbp), %rdi
movl $0x28, %esi
movl $0x14, %edx
callq 0xa460
movl %eax, %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0x18(%rax)
movq -0x28(%rbp), %rdi
movl $0x3c, %esi
movl $0x3, %edx
callq 0xa460
movl %eax, %ecx
subl $0x7, %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0x28(%rax)
movq -0x30(%rbp), %rdi
movl $0x20, %esi
movl $0xa, %edx
callq 0xa460
movw %ax, %cx
movq -0x10(%rbp), %rax
movw %cx, 0x2c(%rax)
movq -0x30(%rbp), %rdi
movl $0x2a, %esi
movl $0xa, %edx
callq 0xa460
movw %ax, %cx
movq -0x10(%rbp), %rax
movw %cx, 0x2e(%rax)
movq -0x30(%rbp), %rdi
movl $0x34, %esi
movl $0xa, %edx
callq 0xa460
movw %ax, %cx
movq -0x10(%rbp), %rax
movw %cx, 0x30(%rax)
movq -0x10(%rbp), %rax
movl 0x14(%rax), %ecx
movq -0x10(%rbp), %rax
addl 0x18(%rax), %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0x8(%rax)
movq -0x10(%rbp), %rax
addq $0x32, %rax
movq %rax, -0x38(%rbp)
movq -0x18(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x40(%rbp)
movq -0x18(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x30(%rbp), %rdi
xorl %esi, %esi
movl $0x20, %edx
callq 0xa460
movl %eax, %ecx
movq -0x60(%rbp), %rax
movl %ecx, %ecx
addq %rcx, %rax
movq %rax, -0x48(%rbp)
movl $0x0, -0x4c(%rbp)
movl $0x0, -0x50(%rbp)
movq -0x48(%rbp), %rax
cmpq -0x40(%rbp), %rax
jne 0x95e8
movl $0x0, -0x4(%rbp)
jmp 0x96c5
movl $0x0, -0x54(%rbp)
cmpl $0x168, -0x54(%rbp)     # imm = 0x168
jge 0x96a5
jmp 0x95fe
movq -0x40(%rbp), %rcx
xorl %eax, %eax
cmpq -0x48(%rbp), %rcx
movb %al, -0x61(%rbp)
jae 0x961c
movl -0x50(%rbp), %eax
addl $0x8, %eax
cmpl $0x20, %eax
setle %al
movb %al, -0x61(%rbp)
movb -0x61(%rbp), %al
testb $0x1, %al
jne 0x9625
jmp 0x964e
movq -0x40(%rbp), %rax
movzbl (%rax), %eax
movl -0x50(%rbp), %ecx
shll %cl, %eax
orl -0x4c(%rbp), %eax
movl %eax, -0x4c(%rbp)
movl -0x50(%rbp), %eax
addl $0x8, %eax
movl %eax, -0x50(%rbp)
movq -0x40(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x40(%rbp)
jmp 0x95fe
movl $0x0, -0x58(%rbp)
movl -0x4c(%rbp), %edi
leaq -0x58(%rbp), %rsi
callq 0xa4f0
movw %ax, %dx
movq -0x38(%rbp), %rax
movslq -0x54(%rbp), %rcx
movw %dx, (%rax,%rcx,2)
movl -0x58(%rbp), %eax
cmpl -0x50(%rbp), %eax
jle 0x9681
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x96c5
movl -0x58(%rbp), %ecx
movl -0x4c(%rbp), %eax
shrl %cl, %eax
movl %eax, -0x4c(%rbp)
movl -0x58(%rbp), %ecx
movl -0x50(%rbp), %eax
subl %ecx, %eax
movl %eax, -0x50(%rbp)
movl -0x54(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x54(%rbp)
jmp 0x95ef
cmpl $0x8, -0x50(%rbp)
jge 0x96b5
movq -0x40(%rbp), %rax
cmpq -0x48(%rbp), %rax
je 0x96be
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x96c5
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x70, %rsp
popq %rbp
retq
nop