// File: tomfunkhouser[P]gaps/pkgs/png/deflate.c
// Function: longest_match
local uInt longest_match(s, cur_match)
    deflate_state *s;
    IPos cur_match;                             /* current match */
{
    unsigned chain_length = s->max_chain_length;/* max hash chain length */
    register Bytef *scan = s->window + s->strstart; /* current string */
    register Bytef *match;                       /* matched string */
    register int len;                           /* length of current match */
    int best_len = s->prev_length;              /* best match length so far */
    int nice_match = s->nice_match;             /* stop if match long enough */
    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
        s->strstart - (IPos)MAX_DIST(s) : NIL;
    /* Stop when cur_match becomes <= limit. To simplify the code,
     * we prevent matches with the string of window index 0.
     */
    Posf *prev = s->prev;
    uInt wmask = s->w_mask;

#ifdef UNALIGNED_OK
    /* Compare two bytes at a time. Note: this is not always beneficial.
     * Try with and without -DUNALIGNED_OK to check.
     */
    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
    register ush scan_start = *(ushf*)scan;
    register ush scan_end   = *(ushf*)(scan+best_len-1);
#else
    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
    register Byte scan_end1  = scan[best_len-1];
    register Byte scan_end   = scan[best_len];
#endif

    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
     * It is easy to get rid of this optimization if necessary.
     */
    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");

    /* Do not waste too much time if we already have a good match: */
    if (s->prev_length >= s->good_match) {
        chain_length >>= 2;
    }
    /* Do not look for matches beyond the end of the input. This is necessary
     * to make deflate deterministic.
     */
    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;

    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");

    do {
        Assert(cur_match < s->strstart, "no future");
        match = s->window + cur_match;

        /* Skip to next match if the match length cannot increase
         * or if the match length is less than 2.  Note that the checks below
         * for insufficient lookahead only occur occasionally for performance
         * reasons.  Therefore uninitialized memory will be accessed, and
         * conditional jumps will be made that depend on those values.
         * However the length of the match is limited to the lookahead, so
         * the output of deflate is not affected by the uninitialized values.
         */
#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
        /* This code assumes sizeof(unsigned short) == 2. Do not use
         * UNALIGNED_OK if your compiler uses a different size.
         */
        if (*(ushf*)(match+best_len-1) != scan_end ||
            *(ushf*)match != scan_start) continue;

        /* It is not necessary to compare scan[2] and match[2] since they are
         * always equal when the other bytes match, given that the hash keys
         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
         * strstart+3, +5, ... up to strstart+257. We check for insufficient
         * lookahead only every 4th comparison; the 128th check will be made
         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
         * necessary to put more guard bytes at the end of the window, or
         * to check more often for insufficient lookahead.
         */
        Assert(scan[2] == match[2], "scan[2]?");
        scan++, match++;
        do {
        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
                 scan < strend);
        /* The funny "do {}" generates better code on most compilers */

        /* Here, scan <= window+strstart+257 */
        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
        if (*scan == *match) scan++;

        len = (MAX_MATCH - 1) - (int)(strend-scan);
        scan = strend - (MAX_MATCH-1);

#else /* UNALIGNED_OK */

        if (match[best_len]   != scan_end  ||
            match[best_len-1] != scan_end1 ||
            *match            != *scan     ||
            *++match          != scan[1])      continue;

        /* The check at best_len-1 can be removed because it will be made
         * again later. (This heuristic is not always a win.)
         * It is not necessary to compare scan[2] and match[2] since they
         * are always equal when the other bytes match, given that
         * the hash keys are equal and that HASH_BITS >= 8.
         */
        scan += 2, match++;
        Assert(*scan == *match, "match[2]?");

        /* We check for insufficient lookahead only every 8th comparison;
         * the 256th check will be made at strstart+258.
         */
        do {
        } while (*++scan == *++match && *++scan == *++match &&
                 *++scan == *++match && *++scan == *++match &&
                 *++scan == *++match && *++scan == *++match &&
                 *++scan == *++match && *++scan == *++match &&
                 scan < strend);

        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");

        len = MAX_MATCH - (int)(strend - scan);
        scan = strend - MAX_MATCH;

#endif /* UNALIGNED_OK */

        if (len > best_len) {
            s->match_start = cur_match;
            best_len = len;
            if (len >= nice_match) break;
#ifdef UNALIGNED_OK
            scan_end = *(ushf*)(scan+best_len-1);
#else
            scan_end1  = scan[best_len-1];
            scan_end   = scan[best_len];
#endif
        }
    } while ((cur_match = prev[cur_match & wmask]) > limit
             && --chain_length != 0);

    if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
    return s->lookahead;
}

// Assembly:
movq %rdi, -0x10(%rsp)
movl %esi, -0x14(%rsp)
movq -0x10(%rsp), %rax
movl 0xac(%rax), %eax
movl %eax, -0x18(%rsp)
movq -0x10(%rsp), %rax
movq 0x50(%rax), %rax
movq -0x10(%rsp), %rcx
movl 0x9c(%rcx), %ecx
addq %rcx, %rax
movq %rax, -0x20(%rsp)
movq -0x10(%rsp), %rax
movl 0xa8(%rax), %eax
movl %eax, -0x30(%rsp)
movq -0x10(%rsp), %rax
movl 0xc0(%rax), %eax
movl %eax, -0x34(%rsp)
movq -0x10(%rsp), %rax
movl 0x9c(%rax), %eax
movq -0x10(%rsp), %rcx
movl 0x44(%rcx), %ecx
subl $0x106, %ecx            # imm = 0x106
cmpl %ecx, %eax
jbe 0x1199a0
movq -0x10(%rsp), %rax
movl 0x9c(%rax), %eax
movq -0x10(%rsp), %rcx
movl 0x44(%rcx), %ecx
subl $0x106, %ecx            # imm = 0x106
subl %ecx, %eax
movl %eax, -0x58(%rsp)
jmp 0x1199a8
xorl %eax, %eax
movl %eax, -0x58(%rsp)
jmp 0x1199a8
movl -0x58(%rsp), %eax
movl %eax, -0x38(%rsp)
movq -0x10(%rsp), %rax
movq 0x60(%rax), %rax
movq %rax, -0x40(%rsp)
movq -0x10(%rsp), %rax
movl 0x4c(%rax), %eax
movl %eax, -0x44(%rsp)
movq -0x10(%rsp), %rax
movq 0x50(%rax), %rax
movq -0x10(%rsp), %rcx
movl 0x9c(%rcx), %ecx
addq %rcx, %rax
addq $0x102, %rax            # imm = 0x102
movq %rax, -0x50(%rsp)
movq -0x20(%rsp), %rax
movl -0x30(%rsp), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
movb (%rax,%rcx), %al
movb %al, -0x51(%rsp)
movq -0x20(%rsp), %rax
movslq -0x30(%rsp), %rcx
movb (%rax,%rcx), %al
movb %al, -0x52(%rsp)
movq -0x10(%rsp), %rax
movl 0xa8(%rax), %eax
movq -0x10(%rsp), %rcx
cmpl 0xbc(%rcx), %eax
jb 0x119a36
movl -0x18(%rsp), %eax
shrl $0x2, %eax
movl %eax, -0x18(%rsp)
movl -0x34(%rsp), %eax
movq -0x10(%rsp), %rcx
cmpl 0xa4(%rcx), %eax
jbe 0x119a56
movq -0x10(%rsp), %rax
movl 0xa4(%rax), %eax
movl %eax, -0x34(%rsp)
jmp 0x119a58
movq -0x10(%rsp), %rax
movq 0x50(%rax), %rax
movl -0x14(%rsp), %ecx
addq %rcx, %rax
movq %rax, -0x28(%rsp)
movq -0x28(%rsp), %rax
movslq -0x30(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movzbl -0x52(%rsp), %ecx
cmpl %ecx, %eax
jne 0x119ad6
movq -0x28(%rsp), %rax
movl -0x30(%rsp), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
movzbl (%rax,%rcx), %eax
movzbl -0x51(%rsp), %ecx
cmpl %ecx, %eax
jne 0x119ad6
movq -0x28(%rsp), %rax
movzbl (%rax), %eax
movq -0x20(%rsp), %rcx
movzbl (%rcx), %ecx
cmpl %ecx, %eax
jne 0x119ad6
movq -0x28(%rsp), %rax
movq %rax, %rcx
addq $0x1, %rcx
movq %rcx, -0x28(%rsp)
movzbl 0x1(%rax), %eax
movq -0x20(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
cmpl %ecx, %eax
je 0x119adb
jmp 0x119d4a
movq -0x20(%rsp), %rax
addq $0x2, %rax
movq %rax, -0x20(%rsp)
movq -0x28(%rsp), %rax
addq $0x1, %rax
movq %rax, -0x28(%rsp)
jmp 0x119af9
movq -0x20(%rsp), %rax
movq %rax, %rcx
addq $0x1, %rcx
movq %rcx, -0x20(%rsp)
movzbl 0x1(%rax), %ecx
movq -0x28(%rsp), %rax
movq %rax, %rdx
addq $0x1, %rdx
movq %rdx, -0x28(%rsp)
movzbl 0x1(%rax), %edx
xorl %eax, %eax
cmpl %edx, %ecx
movb %al, -0x59(%rsp)
jne 0x119cbe
movq -0x20(%rsp), %rax
movq %rax, %rcx
addq $0x1, %rcx
movq %rcx, -0x20(%rsp)
movzbl 0x1(%rax), %ecx
movq -0x28(%rsp), %rax
movq %rax, %rdx
addq $0x1, %rdx
movq %rdx, -0x28(%rsp)
movzbl 0x1(%rax), %edx
xorl %eax, %eax
cmpl %edx, %ecx
movb %al, -0x59(%rsp)
jne 0x119cbe
movq -0x20(%rsp), %rax
movq %rax, %rcx
addq $0x1, %rcx
movq %rcx, -0x20(%rsp)
movzbl 0x1(%rax), %ecx
movq -0x28(%rsp), %rax
movq %rax, %rdx
addq $0x1, %rdx
movq %rdx, -0x28(%rsp)
movzbl 0x1(%rax), %edx
xorl %eax, %eax
cmpl %edx, %ecx
movb %al, -0x59(%rsp)
jne 0x119cbe
movq -0x20(%rsp), %rax
movq %rax, %rcx
addq $0x1, %rcx
movq %rcx, -0x20(%rsp)
movzbl 0x1(%rax), %ecx
movq -0x28(%rsp), %rax
movq %rax, %rdx
addq $0x1, %rdx
movq %rdx, -0x28(%rsp)
movzbl 0x1(%rax), %edx
xorl %eax, %eax
cmpl %edx, %ecx
movb %al, -0x59(%rsp)
jne 0x119cbe
movq -0x20(%rsp), %rax
movq %rax, %rcx
addq $0x1, %rcx
movq %rcx, -0x20(%rsp)
movzbl 0x1(%rax), %ecx
movq -0x28(%rsp), %rax
movq %rax, %rdx
addq $0x1, %rdx
movq %rdx, -0x28(%rsp)
movzbl 0x1(%rax), %edx
xorl %eax, %eax
cmpl %edx, %ecx
movb %al, -0x59(%rsp)
jne 0x119cbe
movq -0x20(%rsp), %rax
movq %rax, %rcx
addq $0x1, %rcx
movq %rcx, -0x20(%rsp)
movzbl 0x1(%rax), %ecx
movq -0x28(%rsp), %rax
movq %rax, %rdx
addq $0x1, %rdx
movq %rdx, -0x28(%rsp)
movzbl 0x1(%rax), %edx
xorl %eax, %eax
cmpl %edx, %ecx
movb %al, -0x59(%rsp)
jne 0x119cbe
movq -0x20(%rsp), %rax
movq %rax, %rcx
addq $0x1, %rcx
movq %rcx, -0x20(%rsp)
movzbl 0x1(%rax), %ecx
movq -0x28(%rsp), %rax
movq %rax, %rdx
addq $0x1, %rdx
movq %rdx, -0x28(%rsp)
movzbl 0x1(%rax), %edx
xorl %eax, %eax
cmpl %edx, %ecx
movb %al, -0x59(%rsp)
jne 0x119cbe
movq -0x20(%rsp), %rax
movq %rax, %rcx
addq $0x1, %rcx
movq %rcx, -0x20(%rsp)
movzbl 0x1(%rax), %ecx
movq -0x28(%rsp), %rax
movq %rax, %rdx
addq $0x1, %rdx
movq %rdx, -0x28(%rsp)
movzbl 0x1(%rax), %edx
xorl %eax, %eax
cmpl %edx, %ecx
movb %al, -0x59(%rsp)
jne 0x119cbe
movq -0x20(%rsp), %rax
cmpq -0x50(%rsp), %rax
setb %al
movb %al, -0x59(%rsp)
movb -0x59(%rsp), %al
testb $0x1, %al
jne 0x119af7
movq -0x50(%rsp), %rax
movq -0x20(%rsp), %rcx
subq %rcx, %rax
movl %eax, %ecx
movl $0x102, %eax            # imm = 0x102
subl %ecx, %eax
movl %eax, -0x2c(%rsp)
movq -0x50(%rsp), %rax
addq $-0x102, %rax           # imm = 0xFEFE
movq %rax, -0x20(%rsp)
movl -0x2c(%rsp), %eax
cmpl -0x30(%rsp), %eax
jle 0x119d48
movl -0x14(%rsp), %ecx
movq -0x10(%rsp), %rax
movl %ecx, 0xa0(%rax)
movl -0x2c(%rsp), %eax
movl %eax, -0x30(%rsp)
movl -0x2c(%rsp), %eax
cmpl -0x34(%rsp), %eax
jl 0x119d21
jmp 0x119d8e
movq -0x20(%rsp), %rax
movl -0x30(%rsp), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
movb (%rax,%rcx), %al
movb %al, -0x51(%rsp)
movq -0x20(%rsp), %rax
movslq -0x30(%rsp), %rcx
movb (%rax,%rcx), %al
movb %al, -0x52(%rsp)
jmp 0x119d4a
movq -0x40(%rsp), %rax
movl -0x14(%rsp), %ecx
andl -0x44(%rsp), %ecx
movl %ecx, %ecx
movzwl (%rax,%rcx,2), %ecx
movl %ecx, -0x14(%rsp)
xorl %eax, %eax
cmpl -0x38(%rsp), %ecx
movb %al, -0x5a(%rsp)
jbe 0x119d82
movl -0x18(%rsp), %eax
addl $-0x1, %eax
movl %eax, -0x18(%rsp)
cmpl $0x0, %eax
setne %al
movb %al, -0x5a(%rsp)
movb -0x5a(%rsp), %al
testb $0x1, %al
jne 0x119a58
movl -0x30(%rsp), %eax
movq -0x10(%rsp), %rcx
cmpl 0xa4(%rcx), %eax
ja 0x119da9
movl -0x30(%rsp), %eax
movl %eax, -0x4(%rsp)
jmp 0x119db8
movq -0x10(%rsp), %rax
movl 0xa4(%rax), %eax
movl %eax, -0x4(%rsp)
movl -0x4(%rsp), %eax
retq
nopl (%rax)