// File: /workspace/github_c_makefile_star2_O3/salextpuru[P]speccy-toochain/src/mhmt/mhmt-lz.c
// Function: make_lz_codes
void make_lz_codes(ULONG position, ULONG actual_len, UBYTE * hash, struct lzcode * codes)
{
    ULONG codepos;
    ULONG codelen,i;
    ULONG was_match;
    UBYTE curr_byte,next_byte;
    struct tb_chain * curr_tb;
    UWORD index;
    ULONG max_lookback,max_length,max_tbdisp;
    // copy-byte code is always present
    codes[0].length = 1;
    codes[0].disp   = 0;
    // start more filling of codes[] from that position
    codepos = 1;

    if( wrk.packtype==PK_HST ) { // for hrust only,
        // add 12,14,16,...,40,42 bytes copies, if possible
        for(codelen=12; codelen<=42; codelen+=2) {
            if( position <= (actual_len-codelen) ) {
                codes[codepos].length = codelen;
                codes[codepos].disp   = 0;
                codepos++;

            } else
                break;
        }
    }

    // check for one-byter (-1..-8)
    //
    curr_byte=wrk.indata[position];
    //
    i = (position>8) ? position-8 : 0;

    do {
        if( wrk.indata[i] == curr_byte ) {
            codes[codepos].length = 1;
            codes[codepos].disp   = -(LONG)(position-i);
            codepos++;
            break;
        }
    } while( (++i)<position );

    // for hrust, check 3-byte insertion code (-1..-79)
    if( (wrk.packtype==PK_HST) && (position < (actual_len-2)) ) {
        i = (position>79) ? position-79 : 0;

        do {
            if( (wrk.indata[i]==curr_byte) && (wrk.indata[i+2]==wrk.indata[position+2]) ) {
                codes[codepos].length = (-3);
                codes[codepos].disp   = -(LONG)(position-i);
                codepos++;
                break;
            }
        } while( (++i)<position );
    }

    switch( wrk.packtype ) { // set maximum lookback and length
    case PK_MLZ:
        max_lookback = (wrk.maxwin<4352) ? wrk.maxwin : 4352;
        max_length = 255;
        max_tbdisp = 256;
        break;

    case PK_HRM:
        max_lookback = (wrk.maxwin<4096) ? wrk.maxwin : 4096;
        max_length = 255;
        max_tbdisp = 256;
        break;

    case PK_HST:
        max_lookback = (wrk.maxwin<65536) ? wrk.maxwin : 65536;
        max_length = 3839;
        max_tbdisp = 768;
        break;

    default:
        printf("mhmt-lz.c:make_lz_codes() - wrong packer type!\n");
        exit(1);
    }

    // check for two-byter (-1..-max_tbdisp)
    //
    curr_tb = NULL;

    //
    if( position<(actual_len-1) ) { // don't try two-byter if we are at the byte before last one
        next_byte = wrk.indata[position+1];
        index=(curr_byte<<8) + next_byte;
        curr_tb = tb_entry[index];

        // there are two-byters!
        if( curr_tb ) {
            if( ((position-curr_tb->pos)<=max_tbdisp) && ((position-curr_tb->pos)<=max_lookback) ) {
                codes[codepos].length = 2;
                codes[codepos].disp   = -(LONG)(position - curr_tb->pos);
                codepos++;
            }
        }
    }

    // at last, check for lengths=3..max_length up to max_lookback
    if(  curr_tb  &&  ( (position-curr_tb->pos)<=max_lookback )  &&  ( position<(actual_len-2) )  ) { // if we can proceed at all
        was_match = 1; // there was match at codelen-1

        for( codelen=3; ( codelen<=max_length )&&( position<(actual_len-codelen+1) ); /*nothing*/ ) {
            if( was_match ) { // for codelen-1
                // codelen-1 bytes are matched, compare one more byte
                if( wrk.indata[position+codelen-1] == wrk.indata[curr_tb->pos+codelen-1] ) {
                    // add code to the table
                    codes[codepos].length = codelen;
                    codes[codepos].disp   = -(LONG)(position - curr_tb->pos);
                    codepos++;
                    codelen++; // next time do comparision of greater size

                } else { // last bytes do not match
MATCH_FAIL: // entrance for failed matches here: used 3-fold so we set "goto" here
                    // go for older twobyter
                    curr_tb = curr_tb->next;

                    // no more twobyters or they are too far - stop search at all
                    if( !curr_tb ) break;

                    if( (position - curr_tb->pos)>max_lookback ) break;

                    // mark there was no matches
                    was_match = 0;
                }

            } else { // there were no matches for previous codelen
                // next twobyter is already taken, but no comparision is done for codelen bytes
                // first we check if we need to do such comparision at all by seeing to the hashes of the ends of strings
                if( hash[position+codelen-1] == hash[curr_tb->pos+codelen-1] ) {
                    // hashes match, so try matching complete string
                    if( !memcmp( &wrk.indata[position], &wrk.indata[curr_tb->pos], codelen ) ) {
                        was_match = 1;
                        codes[codepos].length = codelen;
                        codes[codepos].disp   = -(LONG)(position - curr_tb->pos);
                        codepos++;
                        codelen++;

                    } else
                        // no match of whole string
                        goto MATCH_FAIL;

                } else
                    // no match of hashes
                    goto MATCH_FAIL;
            }
        }
    }

    // here we assume to have found all possible matches. check for codes[] table overflow:
    // there could be matches for length 1..3839, and there is copy-1-byte, 16 copymanybyters, 1 insertion match, total 3857 entries for hrust, 256 for megalz & hrum
    if(   codepos > ( (wrk.packtype==PK_HST) ? 3857 : 256 )   ) { // this should not happen!
        printf("mhmt-lz.c:make_lz_codes_hrust() encountered too many entries in codes[] table. Fatal error.\n");
        exit(1);
    }

    // mark end-of-records in codes[]
    codes[codepos].length = 0;
    codes[codepos].disp   = 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movq %rcx, %rbx
movl %esi, %r9d
movl %edi, %r12d
movq $0x1, (%rcx)
leaq 0x8ab7(%rip), %rax      # 0xb320
movl (%rax), %r11d
cmpl $0x3, %r11d
setne %cl
leal -0xc(%r9), %esi
cmpl %edi, %esi
setb %sil
movl $0x1, %r13d
orb %cl, %sil
jne 0x28b9
leal -0xe(%r9), %edi
movl $0xc, %ecx
movl $0x1, %r13d
movl %ecx, (%rbx,%r13,8)
movl $0x0, 0x4(%rbx,%r13,8)
incq %r13
cmpl $0x28, %ecx
ja 0x28b9
addl $0x2, %ecx
leal -0x2(%rdi), %esi
cmpl %r12d, %edi
movl %esi, %edi
jae 0x2897
movq 0x40(%rax), %r14
movl %r12d, %r15d
leaq (%r14,%r15), %rcx
movq %rcx, 0x28(%rsp)
movzbl (%r14,%r15), %ecx
xorl %edi, %edi
movl %r12d, %esi
subl $0x8, %esi
cmovbl %edi, %esi
movl $0x8, %edi
cmovbl %r12d, %edi
negl %edi
cmpb %cl, (%r14,%rsi)
je 0x28f6
incq %rsi
incl %edi
cmpq %r15, %rsi
jb 0x28e4
jmp 0x2907
movl %r13d, %esi
movl $0x1, (%rbx,%rsi,8)
movl %edi, 0x4(%rbx,%rsi,8)
incl %r13d
cmpl $0x3, %r11d
setne %dil
leal -0x2(%r9), %esi
cmpl %r12d, %esi
setbe %r8b
orb %dil, %r8b
jne 0x2978
movq %r9, %rbp
leal 0x2(%r12), %edi
xorl %r9d, %r9d
movl %r12d, %r8d
subl $0x4f, %r8d
cmovbl %r9d, %r8d
movl $0x4f, %r9d
cmovbl %r12d, %r9d
negl %r9d
cmpb %cl, (%r14,%r8)
jne 0x2956
leal 0x2(%r8), %r10d
movb (%r14,%r10), %r10b
cmpb (%r14,%rdi), %r10b
je 0x2963
incq %r8
incl %r9d
cmpq %r15, %r8
jb 0x2942
jmp 0x2975
movl %r13d, %edi
movl $0xfffffffd, (%rbx,%rdi,8) # imm = 0xFFFFFFFD
movl %r9d, 0x4(%rbx,%rdi,8)
incl %r13d
movq %rbp, %r9
cmpl $0x3, %r11d
je 0x29b6
cmpl $0x2, %r11d
je 0x2999
cmpl $0x1, %r11d
jne 0x2b47
movl 0x1c(%rax), %eax
movl $0x1100, %r8d           # imm = 0x1100
jmp 0x29a2
movl 0x1c(%rax), %eax
movl $0x1000, %r8d           # imm = 0x1000
cmpl %r8d, %eax
cmovbl %eax, %r8d
movl $0x100, %eax            # imm = 0x100
movl $0xff, %r10d
jmp 0x29d1
movl 0x1c(%rax), %eax
movl $0x10000, %r8d          # imm = 0x10000
cmpl %r8d, %eax
cmovbl %eax, %r8d
movl $0x300, %eax            # imm = 0x300
movl $0xeff, %r10d           # imm = 0xEFF
leal -0x1(%r9), %edi
cmpl %r12d, %edi
jbe 0x2b0e
movzbl 0x1(%r15,%r14), %edi
shll $0xb, %ecx
leal (%rcx,%rdi,8), %ecx
leaq 0x1022f(%rip), %rdi     # 0x12c20
movq (%rdi,%rcx), %r15
testq %r15, %r15
je 0x2b0e
movl (%r15), %edi
movl %r12d, %ecx
subl %edi, %ecx
cmpl %eax, %ecx
ja 0x2a27
cmpl %r8d, %ecx
ja 0x2a27
movl %r13d, %eax
movl $0x2, (%rbx,%rax,8)
movl %edi, %ebp
subl %r12d, %edi
movl %edi, 0x4(%rbx,%rax,8)
movl %ebp, %edi
incl %r13d
cmpl %r12d, %esi
jbe 0x2b0e
cmpl %r8d, %ecx
ja 0x2b0e
movq %rdx, 0x20(%rsp)
incl %r9d
leal -0x1(%r12), %eax
movq %rax, 0x30(%rsp)
movl $0x1, %eax
movl $0x3, %ebp
movl %r11d, 0x10(%rsp)
movq %r9, 0x18(%rsp)
movl %r8d, 0xc(%rsp)
movl %r10d, 0x8(%rsp)
movl %r9d, %ecx
subl %ebp, %ecx
cmpl %r12d, %ecx
jbe 0x2b0e
movq 0x30(%rsp), %rcx
leal (%rcx,%rbp), %edx
leal -0x1(%rbp), %ecx
testl %eax, %eax
je 0x2aad
movb (%r14,%rdx), %al
addl %edi, %ecx
cmpb (%r14,%rcx), %al
jne 0x2aed
movl %r13d, %eax
movl %ebp, (%rbx,%rax,8)
movl %edi, %ecx
subl %r12d, %ecx
movl %ecx, 0x4(%rbx,%rax,8)
incl %r13d
incl %ebp
movl $0x1, %eax
jmp 0x2b05
movq 0x20(%rsp), %rsi
movb (%rsi,%rdx), %al
addl %edi, %ecx
cmpb (%rsi,%rcx), %al
jne 0x2aed
movl %edi, %esi
addq %r14, %rsi
movl %ebp, %edx
movl %edi, 0x14(%rsp)
movq 0x28(%rsp), %rdi
callq 0x1090
movl 0x14(%rsp), %edi
movl 0x8(%rsp), %r10d
movl 0xc(%rsp), %r8d
movq 0x18(%rsp), %r9
movl 0x10(%rsp), %r11d
testl %eax, %eax
je 0x2a92
movq 0x8(%r15), %r15
testq %r15, %r15
je 0x2b0e
movl (%r15), %edi
movl %r12d, %ecx
subl %edi, %ecx
xorl %eax, %eax
cmpl %r8d, %ecx
ja 0x2b0e
cmpl %r10d, %ebp
jbe 0x2a69
cmpl $0x3, %r11d
movl $0xf11, %eax            # imm = 0xF11
movl $0x100, %ecx            # imm = 0x100
cmovel %eax, %ecx
cmpl %ecx, %r13d
ja 0x2b3e
movl %r13d, %eax
movq $0x0, (%rbx,%rax,8)
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x3933(%rip), %rdi      # 0x6478
jmp 0x2b4e
leaq 0x3986(%rip), %rdi      # 0x64d4
callq 0x1120
movl $0x1, %edi
callq 0x10d0