// File: /workspace/github_cpp_makefile_star2_O2/sbingner[P]kerneldec/lzfse/src/lzvn_encode_base.c
// Function: lzvn_encode
void lzvn_encode(lzvn_encoder_state *state) {
  const lzvn_match_info NO_MATCH = {0};

  for (; state->src_current < state->src_current_end; state->src_current++) {
    // Get 4 bytes at src_current
    uint32_t vi = load4(state->src + state->src_current);

    // Compute new hash H at position I, and push value into position table
    int h = hash3i(vi); // index of first entry

    // Read table entries for H
    lzvn_encode_entry_type e = state->table[h];

    // Update entry with index=current and value=vi
    lzvn_encode_entry_type updated_e; // rotate values, so we will replace the oldest
    updated_e.indices[0] = offset_to_s32(state->src_current);
    updated_e.indices[1] = e.indices[0];
    updated_e.indices[2] = e.indices[1];
    updated_e.indices[3] = e.indices[2];
    updated_e.values[0] = vi;
    updated_e.values[1] = e.values[0];
    updated_e.values[2] = e.values[1];
    updated_e.values[3] = e.values[2];

    // Do not check matches if still in previously emitted match
    if (state->src_current < state->src_literal)
      goto after_emit;

// Update best with candidate if better
#define UPDATE(best, candidate)                                                \
  do {                                                                         \
    if (candidate.K > best.K ||                                                \
        ((candidate.K == best.K) && (candidate.m_end > best.m_end + 1))) {     \
      best = candidate;                                                        \
    }                                                                          \
  } while (0)
// Check candidate. Keep if better.
#define CHECK_CANDIDATE(ik, nk)                                                \
  do {                                                                         \
    lzvn_match_info m1;                                                              \
    if (lzvn_find_matchN(state->src, state->src_begin, state->src_end,               \
                   state->src_literal, ik, state->src_current, nk, &m1)) {     \
      UPDATE(incoming, m1);                                                    \
    }                                                                          \
  } while (0)
// Emit match M. Return if we don't have enough space in the destination buffer
#define EMIT_MATCH(m)                                                          \
  do {                                                                         \
    if (lzvn_emit_match(state, m) == 0)                                              \
      return;                                                                  \
  } while (0)
// Emit literal of length L. Return if we don't have enough space in the
// destination buffer
#define EMIT_LITERAL(l)                                                        \
  do {                                                                         \
    if (lzvn_emit_literal(state, l) == 0)                                            \
      return;                                                                  \
  } while (0)

    lzvn_match_info incoming = NO_MATCH;

    // Check candidates in order (closest first)
    uint32_t diffs[4];
    for (int k = 0; k < 4; k++)
      diffs[k] = e.values[k] ^ vi; // XOR, 0 if equal
    lzvn_offset ik;                // index
    lzvn_offset nk;                // match byte count

    // The values stored in e.xyzw are 32-bit signed indices, extended to signed
    // type lzvn_offset
    ik = offset_from_s32(e.indices[0]);
    nk = trailing_zero_bytes(diffs[0]);
    CHECK_CANDIDATE(ik, nk);
    ik = offset_from_s32(e.indices[1]);
    nk = trailing_zero_bytes(diffs[1]);
    CHECK_CANDIDATE(ik, nk);
    ik = offset_from_s32(e.indices[2]);
    nk = trailing_zero_bytes(diffs[2]);
    CHECK_CANDIDATE(ik, nk);
    ik = offset_from_s32(e.indices[3]);
    nk = trailing_zero_bytes(diffs[3]);
    CHECK_CANDIDATE(ik, nk);

    // Check candidate at previous distance
    if (state->d_prev != 0) {
      lzvn_match_info m1;
      if (lzvn_find_match(state->src, state->src_begin, state->src_end,
                    state->src_literal, state->src_current - state->d_prev,
                    state->src_current, &m1)) {
        m1.K = m1.M - 1; // fix K for D_prev
        UPDATE(incoming, m1);
      }
    }

    // Here we have the best candidate in incoming, may be NO_MATCH

    // If no incoming match, and literal backlog becomes too high, emit pending
    // match, or literals if there is no pending match
    if (incoming.M == 0) {
      if (state->src_current - state->src_literal >=
          LZVN_ENCODE_MAX_LITERAL_BACKLOG) // at this point, we always have
                                           // current >= literal
      {
        if (state->pending.M != 0) {
          EMIT_MATCH(state->pending);
          state->pending = NO_MATCH;
        } else {
          EMIT_LITERAL(271); // emit long literal (271 is the longest literal size we allow)
        }
      }
      goto after_emit;
    }

    if (state->pending.M == 0) {
      // NOTE. Here, we can also emit incoming right away. It will make the
      // encoder 1.5x faster, at a cost of ~10% lower compression ratio:
      // EMIT_MATCH(incoming);
      // state->pending = NO_MATCH;

      // No pending match, emit nothing, keep incoming
      state->pending = incoming;
    } else {
      // Here we have both incoming and pending
      if (state->pending.m_end <= incoming.m_begin) {
        // No overlap: emit pending, keep incoming
        EMIT_MATCH(state->pending);
        state->pending = incoming;
      } else {
        // If pending is better, emit pending and discard incoming.
        // Otherwise, emit incoming and discard pending.
        if (incoming.K > state->pending.K)
          state->pending = incoming;
        EMIT_MATCH(state->pending);
        state->pending = NO_MATCH;
      }
    }

  after_emit:

    // We commit state changes only after we tried to emit instructions, so we
    // can restart in the same state in case dst was full and we quit the loop.
    state->table[h] = updated_e;

  } // i loop

  // Do not emit pending match here. We do it only at the end of stream.
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x128, %rsp            # imm = 0x128
movq %rdi, %rbx
pxor %xmm0, %xmm0
movdqa %xmm0, 0x110(%rsp)
movdqa %xmm0, 0x100(%rsp)
andq $0x0, 0x120(%rsp)
leaq 0x48(%rdi), %rax
movq %rax, 0x70(%rsp)
movq 0x18(%rdi), %r14
pushq $0x4
popq %r11
cmpq 0x20(%rbx), %r14
jge 0x663e
movq (%rbx), %r15
movl (%r15,%r14), %r13d
movl %r13d, %eax
andl $0xffffff, %eax         # imm = 0xFFFFFF
imull $0x1041, %eax, %r12d    # imm = 0x1041
shrl $0xc, %r12d
andl $0x3fff, %r12d          # imm = 0x3FFF
movq 0x78(%rbx), %rax
movl %r12d, %ecx
shll $0x5, %ecx
movdqu (%rax,%rcx), %xmm0
movups 0x10(%rax,%rcx), %xmm1
movdqa %xmm0, 0xd0(%rsp)
movaps %xmm1, 0xe0(%rsp)
movl 0xd0(%rsp), %edx
movl 0xd4(%rsp), %esi
movl 0xd8(%rsp), %edi
movsd 0xe0(%rsp), %xmm2
movl 0xe8(%rsp), %ebp
movq 0x28(%rbx), %rcx
movq %r14, %rax
movq %rcx, 0x78(%rsp)
subq %rcx, %rax
jl 0x65f9
movq %rax, 0xf0(%rsp)
movslq %edx, %r8
movslq %esi, %rax
movq %rax, 0xf8(%rsp)
movslq %edi, %rax
movq %rax, 0x58(%rsp)
pushq $0x4
popq %rax
cmpq $0x8, %rax
je 0x6017
movl 0xd0(%rsp,%rax,4), %ecx
xorl %r13d, %ecx
movl %ecx, 0xb0(%rsp,%rax,4)
incq %rax
jmp 0x5ffb
movl %edi, 0x3c(%rsp)
movl %esi, 0x40(%rsp)
movl %edx, 0x44(%rsp)
movl %ebp, 0x54(%rsp)
movaps %xmm2, 0xb0(%rsp)
movl 0xc0(%rsp), %eax
bsfl %eax, %ecx
shrl $0x3, %ecx
testl %eax, %eax
cmovel %r11d, %ecx
movq 0x8(%rbx), %rsi
movq 0x10(%rbx), %rbp
leaq 0x88(%rsp), %rax
movq %rax, 0x8(%rsp)
movq %rcx, (%rsp)
movq %r15, %rdi
movq %rsi, 0x80(%rsp)
movq %rbp, %rdx
movq 0x78(%rsp), %rcx
movq %r14, %r9
callq 0x6650
testl %eax, %eax
je 0x60c8
movq 0x90(%rsp), %rdx
movq 0xa8(%rsp), %rsi
testq %rsi, %rsi
jg 0x60a0
sete %al
cmpq $0x2, %rdx
setge %cl
andb %al, %cl
cmpb $0x1, %cl
jne 0x60c8
movq %rsi, 0x28(%rsp)
movq %rdx, 0x30(%rsp)
movq 0x88(%rsp), %rax
movq %rax, 0x48(%rsp)
movdqu 0x98(%rsp), %xmm0
movdqa %xmm0, 0x60(%rsp)
jmp 0x60ed
pxor %xmm0, %xmm0
movdqa %xmm0, 0x60(%rsp)
movq $0x0, 0x48(%rsp)
movq $0x0, 0x30(%rsp)
movq $0x0, 0x28(%rsp)
pushq $0x4
popq %rdx
movl 0xc4(%rsp), %eax
bsfl %eax, %ecx
shrl $0x3, %ecx
testl %eax, %eax
cmovel %edx, %ecx
leaq 0x88(%rsp), %rax
movq %rax, 0x8(%rsp)
movq %rcx, (%rsp)
movq %r15, %rdi
movq 0x80(%rsp), %rsi
movq %rbp, %rdx
movq 0x78(%rsp), %rcx
movq 0xf8(%rsp), %r8
movq %r14, %r9
callq 0x6650
testl %eax, %eax
je 0x617c
movq 0xa8(%rsp), %rax
cmpq 0x28(%rsp), %rax
pushq $0x4
popq %rsi
jle 0x6181
movq 0x90(%rsp), %rcx
movq 0x88(%rsp), %rdx
movq %rdx, 0x48(%rsp)
movdqu 0x98(%rsp), %xmm0
movdqa %xmm0, 0x60(%rsp)
movq %rcx, 0x30(%rsp)
movq %rax, 0x28(%rsp)
jmp 0x6198
pushq $0x4
popq %rsi
jmp 0x6198
jne 0x6198
movq 0x90(%rsp), %rcx
movq 0x30(%rsp), %rdx
incq %rdx
cmpq %rdx, %rcx
jg 0x6154
movl 0xc8(%rsp), %eax
bsfl %eax, %ecx
shrl $0x3, %ecx
testl %eax, %eax
cmovel %esi, %ecx
leaq 0x88(%rsp), %rax
movq %rax, 0x8(%rsp)
movq %rcx, (%rsp)
movq %r15, %rdi
movq 0x80(%rsp), %rsi
movq %rbp, %rdx
movq 0x78(%rsp), %rcx
movq 0x58(%rsp), %r8
movq %r14, %r9
callq 0x6650
testl %eax, %eax
je 0x6221
movq 0xa8(%rsp), %rax
cmpq 0x28(%rsp), %rax
pushq $0x4
popq %rsi
jle 0x6226
movq 0x90(%rsp), %rcx
movq 0x88(%rsp), %rdx
movq %rdx, 0x48(%rsp)
movdqu 0x98(%rsp), %xmm0
movdqa %xmm0, 0x60(%rsp)
movq %rcx, 0x30(%rsp)
movq %rax, 0x28(%rsp)
jmp 0x623d
pushq $0x4
popq %rsi
jmp 0x623d
jne 0x623d
movq 0x90(%rsp), %rcx
movq 0x30(%rsp), %rdx
incq %rdx
cmpq %rdx, %rcx
jg 0x61f9
movslq 0xdc(%rsp), %r8
movl 0xcc(%rsp), %eax
bsfl %eax, %ecx
shrl $0x3, %ecx
testl %eax, %eax
cmovel %esi, %ecx
leaq 0x88(%rsp), %rax
movq %rax, 0x8(%rsp)
movq %rcx, (%rsp)
movq %r15, %rdi
movq 0x80(%rsp), %rsi
movq %rbp, %rdx
movq 0x78(%rsp), %rcx
movq %r14, %r9
callq 0x6650
testl %eax, %eax
je 0x62cd
movq 0xa8(%rsp), %rax
movq 0x28(%rsp), %r10
cmpq %r10, %rax
pushq $0x4
popq %r11
movaps 0xb0(%rsp), %xmm2
jle 0x62e0
movq 0x90(%rsp), %rcx
movq 0x88(%rsp), %rdx
movq %rdx, 0x48(%rsp)
movdqu 0x98(%rsp), %xmm0
movq %rcx, 0x30(%rsp)
movq %rax, %r10
jmp 0x6305
pushq $0x4
popq %r11
movaps 0xb0(%rsp), %xmm2
movq 0x28(%rsp), %r10
jmp 0x62ff
jne 0x62ff
movq 0x90(%rsp), %rcx
movq 0x30(%rsp), %rdx
incq %rdx
cmpq %rdx, %rcx
movdqa 0x60(%rsp), %xmm0
jg 0x62ad
jmp 0x6305
movdqa 0x60(%rsp), %xmm0
movq 0x70(%rbx), %rax
movq %xmm0, 0x60(%rsp)
pshufd $0xee, %xmm0, %xmm0     # xmm0 = xmm0[2,3,2,3]
movq %xmm0, 0x58(%rsp)
testq %rax, %rax
je 0x6397
movq %r14, %rcx
subq %rax, %rcx
movl (%r15,%rcx), %ecx
movl %ecx, %edx
xorl %r13d, %edx
bsfl %edx, %esi
shrl $0x3, %esi
cmpl %ecx, %r13d
sete %dil
cmovel %r11d, %esi
leaq -0x10000(%rax), %rcx
cmpq $-0xffff, %rcx          # imm = 0xFFFF0001
jb 0x6397
cmpl $0x3, %esi
jb 0x6397
movq %r14, %rdx
movl %esi, %esi
leaq (%rdx,%rsi), %rcx
testb $0x1, %dil
je 0x63a5
leaq (%rdx,%rsi), %rdi
addq $0x4, %rdi
cmpq %rbp, %rdi
jge 0x63a5
movq %rcx, %rdx
subq %rax, %rdx
movl (%r15,%rcx), %edi
movl (%r15,%rdx), %edx
movl %edx, %esi
xorl %edi, %esi
bsfl %esi, %esi
shrl $0x3, %esi
cmpl %edx, %edi
sete %dil
cmovel %r11d, %esi
movq %rcx, %rdx
jmp 0x6357
movl 0x54(%rsp), %ebp
movq 0x60(%rsp), %r15
jmp 0x6438
movq %r10, 0x28(%rsp)
decq %r15
movq %rax, %r8
negq %r8
movq %r15, %r9
subq %rax, %r9
movq %r14, %rdi
movl 0x54(%rsp), %ebp
leaq (%r8,%rdi), %r10
cmpq 0x80(%rsp), %r10
jle 0x63e4
cmpq 0x78(%rsp), %rdi
jle 0x63e4
movb (%r15,%rdi), %r10b
cmpb (%r9,%rdi), %r10b
jne 0x63e4
decq %rdi
jmp 0x63c0
leaq (%rdx,%rsi), %r8
subq %rdi, %r8
leaq -0x1(%r8), %r9
movq 0x28(%rsp), %r10
cmpq %r10, %r9
movq 0x60(%rsp), %r15
jg 0x6423
subq %rdx, %r10
subq %rsi, %r10
addq %rdi, %r10
cmpq $-0x1, %r10
jne 0x6634
movq 0x30(%rsp), %rdx
incq %rdx
cmpq %rdx, %rcx
movq 0x28(%rsp), %r10
jle 0x6438
movq %rdi, 0x48(%rsp)
movq %rcx, 0x30(%rsp)
movq %r8, %r15
movq %rax, 0x58(%rsp)
movq %r9, %r10
testq %r15, %r15
je 0x648e
cmpq $0x0, 0x58(%rbx)
movl 0x44(%rsp), %edx
movl 0x40(%rsp), %esi
movl 0x3c(%rsp), %edi
je 0x652f
movq 0x48(%rsp), %rax
cmpq %rax, 0x50(%rbx)
jle 0x6557
cmpq 0x68(%rbx), %r10
jle 0x64b7
movq 0x48(%rsp), %rax
movq %rax, 0x48(%rbx)
movq 0x30(%rsp), %rax
movq %rax, 0x50(%rbx)
movq %r15, 0x58(%rbx)
movq 0x58(%rsp), %rax
movq %rax, 0x60(%rbx)
movq %r10, 0x68(%rbx)
jmp 0x64b7
cmpq $0x190, 0xf0(%rsp) # imm = 0x190
movl 0x44(%rsp), %edx
movl 0x40(%rsp), %esi
movl 0x3c(%rsp), %edi
jl 0x65f9
cmpq $0x0, 0x58(%rbx)
je 0x65cf
movq 0x70(%rsp), %rcx
movq 0x20(%rcx), %rax
movq %rax, 0x20(%rsp)
movdqu (%rcx), %xmm0
movups 0x10(%rcx), %xmm1
movups %xmm1, 0x10(%rsp)
movdqu %xmm0, (%rsp)
movq %rbx, %rdi
callq 0x6729
testq %rax, %rax
pushq $0x4
popq %r11
movaps 0xb0(%rsp), %xmm2
movl 0x44(%rsp), %edx
movl 0x40(%rsp), %esi
movl 0x3c(%rsp), %edi
je 0x663e
movq 0x120(%rsp), %rax
movq 0x70(%rsp), %rcx
movq %rax, 0x20(%rcx)
movdqa 0x100(%rsp), %xmm0
movaps 0x110(%rsp), %xmm1
movups %xmm1, 0x10(%rcx)
movdqu %xmm0, (%rcx)
jmp 0x65f9
movq 0x48(%rsp), %rax
movq %rax, 0x48(%rbx)
movq 0x30(%rsp), %rax
movq %rax, 0x50(%rbx)
movq %r15, 0x58(%rbx)
movq 0x58(%rsp), %rax
movq %rax, 0x60(%rbx)
movq %r10, 0x68(%rbx)
jmp 0x65f9
movq %r10, 0x28(%rsp)
movq 0x70(%rsp), %rcx
movq 0x20(%rcx), %rax
movq %rax, 0x20(%rsp)
movdqu (%rcx), %xmm0
movups 0x10(%rcx), %xmm1
movups %xmm1, 0x10(%rsp)
movdqu %xmm0, (%rsp)
movq %rbx, %rdi
callq 0x6729
movl 0x3c(%rsp), %edi
movl 0x40(%rsp), %esi
movl 0x44(%rsp), %edx
movaps 0xb0(%rsp), %xmm2
pushq $0x4
popq %r11
testq %rax, %rax
je 0x663e
movq 0x48(%rsp), %rax
movq %rax, 0x48(%rbx)
movq 0x30(%rsp), %rax
movq %rax, 0x50(%rbx)
movq %r15, 0x58(%rbx)
movq 0x58(%rsp), %rax
movq %rax, 0x60(%rbx)
movq 0x28(%rsp), %rax
movq %rax, 0x68(%rbx)
jmp 0x65f9
movl $0x10f, %esi            # imm = 0x10F
movq %rbx, %rdi
callq 0x696e
testq %rax, %rax
pushq $0x4
popq %r11
movaps 0xb0(%rsp), %xmm2
movl 0x44(%rsp), %edx
movl 0x40(%rsp), %esi
movl 0x3c(%rsp), %edi
je 0x663e
movq 0x78(%rbx), %rax
shll $0x5, %r12d
movl %r14d, (%rax,%r12)
movl %edx, 0x4(%rax,%r12)
movl %esi, 0x8(%rax,%r12)
movl %edi, 0xc(%rax,%r12)
movl %r13d, 0x10(%rax,%r12)
movlps %xmm2, 0x14(%rax,%r12)
movl %ebp, 0x1c(%rax,%r12)
movq 0x18(%rbx), %r14
incq %r14
movq %r14, 0x18(%rbx)
jmp 0x5f50
movq 0x28(%rsp), %r10
jmp 0x6438
addq $0x128, %rsp            # imm = 0x128
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq