// File: /workspace/github_c_makefile_star2_O2/bluecmd[P]fst-example/gtkwave/fastlz.c
// Function: fastlz2_compress
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output)
{
  const flzuint8* ip = (const flzuint8*) input;
  const flzuint8* ip_bound = ip + length - 2;
  const flzuint8* ip_limit = ip + length - 12;
  flzuint8* op = (flzuint8*) output;

  const flzuint8* htab[HASH_SIZE];
  const flzuint8** hslot;
  flzuint32 hval;

  flzuint32 copy;

  /* sanity check */
  if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4))
  {
    if(length)
    {
      /* create literal copy only */
      *op++ = length-1;
      ip_bound++;
      while(ip <= ip_bound)
        *op++ = *ip++;
      return length+1;
    }
    else
      return 0;
  }

  /* initializes hash table */
  for (hslot = htab; hslot < htab + HASH_SIZE; hslot++)
    *hslot = ip;

  /* we start with literal copy */
  copy = 2;
  *op++ = MAX_COPY-1;
  *op++ = *ip++;
  *op++ = *ip++;

  /* main loop */
  while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
  {
    const flzuint8* ref;
    flzuint32 distance;

    /* minimum match length */
    flzuint32 len = 3;

    /* comparison starting-point */
    const flzuint8* anchor = ip;

    /* check for a run */
#if FASTLZ_LEVEL==2
    if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1))
    {
      distance = 1;
      /* ip += 3; */ /* scan-build, never used */
      ref = anchor - 1 + 3;
      goto match;
    }
#endif

    /* find potential match */
    HASH_FUNCTION(hval,ip);
    hslot = htab + hval;
    ref = htab[hval];

    /* calculate distance to the match */
    distance = anchor - ref;

    /* update hash table */
    *hslot = anchor;

    /* is this a match? check the first 3 bytes */
    if(distance==0 ||
#if FASTLZ_LEVEL==1
    (distance >= MAX_DISTANCE) ||
#else
    (distance >= MAX_FARDISTANCE) ||
#endif
    *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++)
      goto literal;

#if FASTLZ_LEVEL==2
    /* far, needs at least 5-byte match */
    if(distance >= MAX_DISTANCE)
    {
      if(*ip++ != *ref++ || *ip++!= *ref++)
        goto literal;
      len += 2;
    }

    match:
#endif

    /* last matched byte */
    ip = anchor + len;

    /* distance is biased */
    distance--;

    if(!distance)
    {
      /* zero distance means a run */
      flzuint8 x = ip[-1];
      while(ip < ip_bound)
        if(*ref++ != x) break; else ip++;
    }
    else
    for(;;)
    {
      /* safe because the outer check against ip limit */
      if(*ref++ != *ip++) break;
      if(*ref++ != *ip++) break;
      if(*ref++ != *ip++) break;
      if(*ref++ != *ip++) break;
      if(*ref++ != *ip++) break;
      if(*ref++ != *ip++) break;
      if(*ref++ != *ip++) break;
      if(*ref++ != *ip++) break;
      while(ip < ip_bound)
        if(*ref++ != *ip++) break;
      break;
    }

    /* if we have copied something, adjust the copy count */
    if(copy)
      /* copy is biased, '0' means 1 byte copy */
      *(op-copy-1) = copy-1;
    else
      /* back, to overwrite the copy count */
      op--;

    /* reset literal counter */
    copy = 0;

    /* length is biased, '1' means a match of 3 bytes */
    ip -= 3;
    len = ip - anchor;

    /* encode the match */
#if FASTLZ_LEVEL==2
    if(distance < MAX_DISTANCE)
    {
      if(len < 7)
      {
        *op++ = (len << 5) + (distance >> 8);
        *op++ = (distance & 255);
      }
      else
      {
        *op++ = (7 << 5) + (distance >> 8);
        for(len-=7; len >= 255; len-= 255)
          *op++ = 255;
        *op++ = len;
        *op++ = (distance & 255);
      }
    }
    else
    {
      /* far away, but not yet in the another galaxy... */
      if(len < 7)
      {
        distance -= MAX_DISTANCE;
        *op++ = (len << 5) + 31;
        *op++ = 255;
        *op++ = distance >> 8;
        *op++ = distance & 255;
      }
      else
      {
        distance -= MAX_DISTANCE;
        *op++ = (7 << 5) + 31;
        for(len-=7; len >= 255; len-= 255)
          *op++ = 255;
        *op++ = len;
        *op++ = 255;
        *op++ = distance >> 8;
        *op++ = distance & 255;
      }
    }
#else

    if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2))
      while(len > MAX_LEN-2)
      {
        *op++ = (7 << 5) + (distance >> 8);
        *op++ = MAX_LEN - 2 - 7 -2;
        *op++ = (distance & 255);
        len -= MAX_LEN-2;
      }

    if(len < 7)
    {
      *op++ = (len << 5) + (distance >> 8);
      *op++ = (distance & 255);
    }
    else
    {
      *op++ = (7 << 5) + (distance >> 8);
      *op++ = len - 7;
      *op++ = (distance & 255);
    }
#endif

    /* update the hash at match boundary */
    HASH_FUNCTION(hval,ip);
    htab[hval] = ip++;
    HASH_FUNCTION(hval,ip);
    htab[hval] = ip++;

    /* assuming literal copy */
    *op++ = MAX_COPY-1;

    continue;

    literal:
      *op++ = *anchor++;
      ip = anchor;
      copy++;
      if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY))
      {
        copy = 0;
        *op++ = MAX_COPY-1;
      }
  }

  /* left-over as literal copy */
  ip_bound++;
  while(ip <= ip_bound)
  {
    *op++ = *ip++;
    copy++;
    if(copy == MAX_COPY)
    {
      copy = 0;
      *op++ = MAX_COPY-1;
    }
  }

  /* if we have copied something, adjust the copy length */
  if(copy)
    *(op-copy-1) = copy-1;
  else
    op--;

#if FASTLZ_LEVEL==2
  /* marker for fastlz2 */
  *(flzuint8*)output |= (1 << 5);
#endif

  return op - (flzuint8*)output;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xff98, %rsp           # imm = 0xFF98
movslq %esi, %rax
leaq (%rdi,%rax), %rcx
cmpl $0x4, %eax
jl 0x2ead
leaq (%rdi,%rax), %r12
addq $-0x2, %r12
leaq (%rdi,%rax), %rsi
addq $-0xc, %rsi
xorl %eax, %eax
cmpq $0xffff, %rax           # imm = 0xFFFF
ja 0x2b2c
movq %rdi, -0x10040(%rbp,%rax)
addq $0x8, %rax
jmp 0x2b16
movq %rcx, -0x38(%rbp)
movb $0x1f, (%rdx)
movb (%rdi), %al
movb %al, 0x1(%rdx)
movb 0x1(%rdi), %al
addq $0x2, %rdi
leaq 0x3(%rdx), %rbx
movq %rdx, -0x30(%rbp)
movb %al, 0x2(%rdx)
movl $0x2, %r10d
movl $0x1, %r8d
movl $0x1fff, %r9d           # imm = 0x1FFF
movq %rbx, %rax
movq %rdi, %r11
cmpq %rsi, %rdi
jae 0x2e45
movb (%r11), %cl
cmpb -0x1(%r11), %cl
jne 0x2bab
movzwl 0x1(%r11), %ecx
cmpw %cx, -0x1(%r11)
jne 0x2bb0
leaq 0x2(%r11), %rbx
leaq 0x3(%r11), %r13
movb 0x2(%r11), %cl
movq %r13, %rdi
xorl %r15d, %r15d
cmpq %r12, %rdi
jae 0x2c57
cmpb %cl, (%rbx)
jne 0x2c57
incq %rbx
incq %rdi
jmp 0x2b8f
movzwl 0x1(%r11), %ecx
movzwl (%r11), %ebx
leaq 0x1(%r11), %rdi
xorl %ebx, %ecx
shrl $0x3, %ebx
xorl %ecx, %ebx
andl $0x1fff, %ebx           # imm = 0x1FFF
movq -0x10040(%rbp,%rbx,8), %rcx
movl %r11d, %r14d
subl %ecx, %r14d
movq %r11, -0x10040(%rbp,%rbx,8)
leal -0x11ffd(%r14), %ebx
cmpl $0xfffee004, %ebx       # imm = 0xFFFEE004
jb 0x2c38
movb (%rcx), %bl
cmpb (%r11), %bl
jne 0x2c38
movb 0x1(%rcx), %bl
cmpb (%rdi), %bl
jne 0x2c38
movb 0x2(%rcx), %bl
cmpb 0x2(%r11), %bl
jne 0x2c38
leaq 0x3(%rcx), %rbx
cmpl $0x1fff, %r14d          # imm = 0x1FFF
jb 0x2d90
movb 0x3(%r11), %r15b
cmpb (%rbx), %r15b
jne 0x2c38
movb 0x4(%r11), %bl
cmpb 0x4(%rcx), %bl
jne 0x2c38
addq $0x5, %rcx
leaq 0x5(%r11), %r13
leal -0x1(%r14), %r15d
movq %rcx, %rbx
jmp 0x2da0
movb (%r11), %cl
leaq 0x1(%rax), %rbx
movb %cl, (%rax)
incl %r10d
cmpl $0x20, %r10d
jne 0x2b5c
addq $0x2, %rax
jmp 0x2d82
movl %r8d, %r14d
testl %r10d, %r10d
je 0x2c6f
leal -0x1(%r10), %ecx
movl %r10d, %r10d
notq %r10
movb %cl, (%r10,%rax)
jmp 0x2c72
decq %rax
leaq -0x3(%rdi), %r10
movq %r10, %rcx
subq %r11, %rcx
cmpl $0x1ffe, %r15d          # imm = 0x1FFE
ja 0x2ca4
cmpl $0x6, %ecx
ja 0x2ccc
shll $0x5, %ecx
movl %r15d, %r11d
shrl $0x8, %r11d
orl %ecx, %r11d
movb %r11b, (%rax)
movb %r15b, 0x1(%rax)
addq $0x2, %rax
jmp 0x2cc7
cmpl $0x6, %ecx
ja 0x2cfb
leal 0xe000(%r14), %ebx
shlb $0x5, %cl
orb $0x1f, %cl
movb %cl, (%rax)
movb $-0x1, 0x1(%rax)
movb %bh, 0x2(%rax)
movb %r14b, 0x3(%rax)
addq $0x4, %rax
movq %rax, %rbx
jmp 0x2d3d
movl %r15d, %r11d
shrl $0x8, %r11d
orb $-0x20, %r11b
movb %r11b, (%rax)
addl $-0x7, %ecx
addq $0x3, %rax
movq %rax, %rbx
cmpl $0xff, %ecx
jb 0x2d1f
movb $-0x1, -0x2(%rbx)
addl $0xffffff01, %ecx       # imm = 0xFFFFFF01
incq %rbx
jmp 0x2ce4
movb $-0x1, (%rax)
addl $-0x7, %ecx
addq $0x5, %rax
movq %rax, %rbx
cmpl $0xff, %ecx
jb 0x2d28
movb $-0x1, -0x4(%rbx)
addl $0xffffff01, %ecx       # imm = 0xFFFFFF01
incq %rbx
jmp 0x2d08
movb %cl, -0x2(%rbx)
movb %r15b, -0x1(%rbx)
jmp 0x2d3d
leal 0xe000(%r14), %eax
movb %cl, -0x4(%rbx)
movb $-0x1, -0x3(%rbx)
movb %ah, -0x2(%rbx)
movb %r14b, -0x1(%rbx)
movzwl -0x3(%rdi), %eax
leaq -0x2(%rdi), %rcx
movzwl -0x2(%rdi), %r11d
movl %eax, %r14d
shrl $0x3, %r14d
xorl %r11d, %eax
xorl %r14d, %eax
andl %r9d, %eax
movq %r10, -0x10040(%rbp,%rax,8)
movzwl -0x1(%rdi), %eax
decq %rdi
xorl %r11d, %eax
shrl $0x3, %r11d
xorl %eax, %r11d
andl %r9d, %r11d
movq %rcx, -0x10040(%rbp,%r11,8)
leaq 0x1(%rbx), %rax
movb $0x1f, (%rbx)
xorl %r10d, %r10d
movq %rax, %rbx
jmp 0x2b5c
leaq 0x3(%r11), %r13
movl %r14d, %r15d
decl %r15d
je 0x2b88
movb (%rbx), %cl
cmpb (%r13), %cl
jne 0x2e16
movb 0x1(%rbx), %cl
cmpb 0x1(%r13), %cl
jne 0x2e1b
movb 0x2(%rbx), %cl
cmpb 0x2(%r13), %cl
jne 0x2e21
movb 0x3(%rbx), %cl
cmpb 0x3(%r13), %cl
jne 0x2e27
movb 0x4(%rbx), %cl
cmpb 0x4(%r13), %cl
jne 0x2e2d
movb 0x5(%rbx), %cl
cmpb 0x5(%r13), %cl
jne 0x2e33
movb 0x6(%rbx), %cl
cmpb 0x6(%r13), %cl
jne 0x2e39
movb 0x7(%rbx), %cl
leaq 0x8(%r13), %rdi
cmpb 0x7(%r13), %cl
jne 0x2c5a
addq $0x8, %rbx
cmpq %r12, %rdi
jae 0x2c5a
movb (%rbx), %r13b
incq %rbx
leaq 0x1(%rdi), %rcx
cmpb (%rdi), %r13b
movq %rcx, %rdi
je 0x2df3
movq %rcx, %rdi
jmp 0x2c5a
incq %r13
jmp 0x2e3d
addq $0x2, %r13
jmp 0x2e3d
addq $0x3, %r13
jmp 0x2e3d
addq $0x4, %r13
jmp 0x2e3d
addq $0x5, %r13
jmp 0x2e3d
addq $0x6, %r13
jmp 0x2e3d
addq $0x7, %r13
movq %r13, %rdi
jmp 0x2c5a
movq -0x38(%rbp), %rdx
decq %rdx
movq %rax, %rsi
cmpq %rdx, %r11
ja 0x2e79
movb (%r11), %cl
incq %r11
leaq 0x1(%rsi), %rax
movb %cl, (%rsi)
incl %r10d
cmpl $0x20, %r10d
jne 0x2e4c
movb $0x1f, 0x1(%rsi)
addq $0x2, %rsi
xorl %r10d, %r10d
movq %rsi, %rax
jmp 0x2e4c
testl %r10d, %r10d
je 0x2e8d
leal -0x1(%r10), %eax
movl %r10d, %ecx
notq %rcx
movb %al, (%rcx,%rsi)
jmp 0x2e90
decq %rsi
movq -0x30(%rbp), %rax
orb $0x20, (%rax)
subl %eax, %esi
movl %esi, %eax
addq $0xff98, %rsp           # imm = 0xFF98
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
testl %esi, %esi
je 0x2ece
leal -0x1(%rsi), %eax
movb %al, (%rdx)
decq %rcx
incq %rdx
cmpq %rcx, %rdi
ja 0x2eca
movb (%rdi), %al
incq %rdi
movb %al, (%rdx)
jmp 0x2eb9
incl %esi
jmp 0x2e99
xorl %esi, %esi
jmp 0x2e99