// File: /workspace/github_c_makefile_star2_O2/salextpuru[P]speccy-toochain/src/mhmt/mhmt-emit.c
// Function: emit_hrust
ULONG emit_hrust(struct optchain * optch, ULONG actual_len)
{
    ULONG position;
    LONG length;
    LONG disp;
    LONG max_disp; // maximum encountered displacement
    ULONG varbits,varlen;
    ULONG success = 1;
    UBYTE wrlen[2];
    ULONG expbitlen = 2; // expandable match: bitlength of displacement
    max_disp = 0;

    // some checks
    if( !optch ) {
        printf("mhmt-emit.c:emit_hrust() - NULL passed!\n");
        return 0;
    }

    // initialize
    success = success && emit_file(NULL, EMIT_FILE_INIT);
    success = success && emit_byte(0, EMIT_BYTE_INIT);
    success = success && emit_bits(0, EMIT_BITS_INIT);

    // manage zx header info
    if( wrk.zxheader ) {
        success = success && emit_file( (UBYTE*)"HR", 2);
        wrlen[0] = wrk.inlen&0x00FF;
        wrlen[1] = (wrk.inlen>>8)&0x00FF;
        success = success && emit_file( wrlen, 2); // unpacked length mod 65536
        success = success && emit_file( wrlen, 2); // packed length - !to be filled later!
        success = success && emit_file( &wrk.indata[wrk.inlen-6], 6); // last bytes
    }

    // schedule first byte to be placed just after first bitstream word
    success = success && emit_byte( wrk.indata[0], EMIT_BYTE_ADD);
    // go emitting codes
    position = 1;

    while( (position<actual_len) && success ) {
#ifdef DBG
        printf("%04x:",position);
#endif
        length = optch[position].code.length;
        disp   = optch[position].code.disp;

        if( length==0 ) {
            printf("mhmt-emit.c:emit_hrust() - encountered stop-code in optimal chain before emitting all data!\n");
            return 0;

        } else if( disp==0 ) { // copy-bytes
            if( length==1 ) { // 1 byte: %1<byte>
                success = success && emit_bits( 0x80000000, 1 );
                success = success && emit_byte( wrk.indata[position], EMIT_BYTE_ADD );

            } else if( (12<=length) && (length<=42) && ( !(length&1) ) ) { // %0110001abcd<byte,byte,...>
                varbits = (length-12)<<27;
                success = success && emit_bits( 0x62000000, 7 );
                success = success && emit_bits( varbits, 4 );
                varlen = 0;

                while( success && (varlen<(ULONG)length) ) {
                    success = success && emit_byte( wrk.indata[position+varlen], EMIT_BYTE_ADD );
                    varlen++;
                }

            } else
                goto INVALID_CODE_HRUST;

        } else if( length==(-3) ) { // insertion code
            if( (-16)<=disp && disp<=(-1) ) { // %011001abcd<byte>
                success = success && emit_bits( 0x64000000, 6 );
                success = success && emit_bits( disp<<(32-4), 4 );

            } else if( (-79)<=disp && disp<(-16) ) {
                if( disp&1 ) { // ffb1..ffef: %01001<byte><byte>
                    success = success && emit_bits( 0x48000000, 5 );
                    varbits = disp&0x00FF;
                    varbits += 15;
                    varbits ^= 3;
                    varbits = ( (varbits>>1)&0x007F ) | ( (varbits<<7)&0x0080 );
                    success = success && emit_byte( (UBYTE)(varbits&0x00FF), EMIT_BYTE_ADD );

                } else { // ffb2..ffee: %00110<byte><byte>
                    success = success && emit_bits( 0x30000000, 5 );
                    varbits = disp&0x00FF;
                    varbits += 15;
                    varbits ^= 2;
                    varbits = ( (varbits>>1)&0x007F ) | ( (varbits<<7)&0x0080 );
                    success = success && emit_byte( (UBYTE)(varbits&0x00FF), EMIT_BYTE_ADD );
                }

            } else
                goto INVALID_CODE_HRUST;

            success = success && emit_byte( wrk.indata[position+1], EMIT_BYTE_ADD );

        } else if( length==1 ) { // %000abc
            if( (-8)<=disp && disp<=(-1) ) {
                success = success && emit_bits( 0x00000000, 3 );
                success = success && emit_bits( disp<<(32-3), 3 );

            } else
                goto INVALID_CODE_HRUST;

        } else if( length==2 ) {
            if( (-32)<=disp && disp<=(-1) ) { // %00111abcde
                success = success && emit_bits( 0x38000000, 5 );
                success = success && emit_bits( disp<<(32-5), 5 );

            } else if( (-256)<=disp && disp<(-32) ) { // %00110<byte>
                success = success && emit_bits( 0x30000000, 5 );
                success = success && emit_byte( (UBYTE)(0x00FF & disp), EMIT_BYTE_ADD );

            } else if( (-512)<=disp && disp<(-256) ) { // %00101<byte>
                success = success && emit_bits( 0x28000000, 5 );
                success = success && emit_byte( (UBYTE)(0x00FF & disp), EMIT_BYTE_ADD );

            } else if( (-768)<=disp && disp<(-512) ) { // %00100<byte>
                success = success && emit_bits( 0x20000000, 5 );
                success = success && emit_byte( (UBYTE)(0x00FF & disp), EMIT_BYTE_ADD );

            } else
                goto INVALID_CODE_HRUST;

        } else if (3<=length && length<=3839 && (-65536)<=disp && disp<=(-1) ) {
            // first see if we need emitting expansion codes
            //  -513.. -1024  (FDFF..FC00) - 2 bits
            //  -1025..-2048  (FBFF..F800) - 3
            //  -2049..-4096  (F7FF..F000) - 4
            //  -4097..-8192  (EFFF..E000) - 5
            //  -8193..-16384 (DFFF..C000) - 6
            // -16385..-32768 (BFFF..8000) - 7
            // -32769..-65536 (7FFF..0000) - 8
            if( disp<(-512) ) {
                varbits = 1024;
                varlen  = 2;

                while( (ULONG)(-disp) > varbits ) {
                    varbits <<= 1;
                    varlen++;
                }

                // emit expansion codes, if necessary: %00110<FE>
                while( varlen>expbitlen ) {
                    success = success && emit_bits( 0x30000000, 5 );
                    success = success && emit_byte( 0x00FE, EMIT_BYTE_ADD );
#ifdef DBG
                    printf("expansion\n");
#endif
                    expbitlen++;
                }
            }

            // emit length
            if( length<=15 ) { // 3..15
                success = success && emit_bits( 0, 1 );

                if( length==3 ) {
                    success = success && emit_bits( 0x80000000, 2 ); // %010

                } else {
                    varlen  = length/3;
                    varbits = length%3;
                    success = success && emit_bits( 0xFFFFFFFF, varlen<<1 );

                    if( length!=15 )
                        success = success && emit_bits( varbits<<(32-2), 2 );
                }

            } else if( length<=127 ) { // 16..127: %0110000abcdefg
                success = success && emit_bits( 0x60000000, 7 );
                success = success && emit_bits( length<<(32-7), 7 );

            } else { // 128..3839
                success = success && emit_bits( 0x60000000, 7 );
                success = success && emit_bits( length<<(32-15), 7 );
                success = success && emit_byte( (UBYTE)(length&0x00FF), EMIT_BYTE_ADD );
            }

            // emit displacement
            if( (-32)<=disp ) { // ffe0..ffff: %10abcde
                success = success && emit_bits( 0x80000000, 2 );
                success = success && emit_bits( disp<<(32-5), 5 );

            } else if( (-256)<=disp ) { // ff00..ffdf: %01<byte>
                success = success && emit_bits( 0x40000000, 2 );
                success = success && emit_byte( (UBYTE)(disp&0x00FF), EMIT_BYTE_ADD );

            } else if( (-512)<=disp ) { // fe00..feff: %00<byte>
                success = success && emit_bits( 0x00000000, 2 );
                success = success && emit_byte( (UBYTE)(disp&0x00FF), EMIT_BYTE_ADD );

            } else { // variable code length: [-65536..-512)
                // displacement itself: %11ab[cdefgh]<byte>
                success = success && emit_bits( 0xC0000000, 2 );
                success = success && emit_bits( disp<<(24-expbitlen), expbitlen );
                success = success && emit_byte( (UBYTE)(disp&0x00FF), EMIT_BYTE_ADD );
            }

        } else {
INVALID_CODE_HRUST:
            printf("mhmt-emit.c:emit_hrust() - invalid code: length=%d, displacement=%d\n",length,disp);
            return 0;
        }

#ifdef DBG

        if( length==(-3) ) {
            printf("insert-match.len=%d,disp=%d\n",(-length),disp);

        } else if( disp==0 ) {
            printf("copy.len=%d\n",length);

        } else {
            printf("match.len=%d,disp=%d\n",length,disp);
        }

#endif

        if( max_disp > disp ) max_disp = disp;

        if( length>0 ) // account for negative length
            position += length;

        else
            position -= length;
    }

    // stop-code: %0110_0000_0011_11
    success = success && emit_bits( 0x603C0000, 14 );
    success = success && emit_bits( 0, EMIT_BITS_FINISH ); // this also flushes emit_byte()
    success = success && emit_file( NULL, EMIT_FILE_FINISH );

    if( success ) {
        printf("Maximum displacement actually used is %d.\n",-max_disp);
        // TODO: patch packed length in file, if zx header
    }

    return success;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
testq %rdi, %rdi
je 0x21ef
movl %esi, %r14d
movq %rdi, %r13
xorl %r15d, %r15d
pushq $-0x1
popq %rsi
xorl %edi, %edi
callq 0x156d
movl $0x0, %ebp
testl %eax, %eax
je 0x1cd8
andl $0x0, 0x86c0(%rip)      # 0xa310
andl $0x0, 0x86bd(%rip)      # 0xa314
xorl %ebp, %ebp
pushq $-0x1
popq %rsi
xorl %edi, %edi
callq 0x1733
leaq 0x86b6(%rip), %rbx      # 0xa320
cmpl %ebp, 0xc(%rbx)
je 0x1cc3
testl %eax, %eax
je 0x1cd8
leaq 0x3442(%rip), %rdi      # 0x50bc
pushq $0x2
popq %rsi
callq 0x156d
movzwl 0x48(%rbx), %ecx
movw %cx, 0x16(%rsp)
testl %eax, %eax
je 0x1cd8
leaq 0x16(%rsp), %rdi
pushq $0x2
popq %rsi
callq 0x156d
testl %eax, %eax
je 0x1cd8
leaq 0x16(%rsp), %rdi
pushq $0x2
popq %rsi
callq 0x156d
testl %eax, %eax
je 0x1cd8
movl 0x48(%rbx), %edi
addl $-0x6, %edi
addq 0x40(%rbx), %rdi
pushq $0x6
popq %rsi
callq 0x156d
testl %eax, %eax
je 0x1cd8
movq 0x40(%rbx), %rax
movzbl (%rax), %edi
pushq $0x2
popq %rsi
callq 0x1678
movl %eax, %ebp
pushq $0x2
popq %rax
pushq $0x1
popq %rcx
movl %eax, 0x4(%rsp)
movl %r14d, 0x18(%rsp)
movq %r13, 0x20(%rsp)
cmpl %r14d, %ecx
jae 0x21f8
testl %ebp, %ebp
je 0x21f8
movl %ecx, 0x1c(%rsp)
movl %ecx, %ebx
movq %rbx, %rax
shlq $0x4, %rax
movl (%r13,%rax), %r12d
testq %r12, %r12
je 0x2246
movl 0x4(%r13,%rax), %r13d
testl %r13d, %r13d
je 0x1d78
cmpq $0x2, %r12
pushq $0x2
popq %rbp
pushq $0x3
popq %rsi
je 0x1e1c
cmpl $0x1, %r12d
je 0x1df7
cmpl $-0x3, %r12d
jne 0x1e4b
cmpl $-0x10, %r13d
jb 0x1eaa
movl $0x64000000, %edi       # imm = 0x64000000
pushq $0x6
popq %rsi
callq 0x1733
testl %eax, %eax
je 0x2096
movl %r13d, %edi
shll $0x1c, %edi
pushq $0x4
popq %rsi
callq 0x1733
jmp 0x2036
cmpl $0x1, %r12d
pushq $0x2
popq %rbp
jne 0x1daa
movl $0x80000000, %edi       # imm = 0x80000000
pushq $0x1
popq %rsi
callq 0x1733
testl %eax, %eax
je 0x2096
leaq 0x8583(%rip), %rax      # 0xa320
movq 0x40(%rax), %rax
movzbl (%rax,%rbx), %edi
jmp 0x2088
leal -0xc(%r12), %eax
cmpl $0x1e, %eax
ja 0x2265
movl %r12d, %eax
andl $0x1, %eax
jne 0x2265
movl $0x62000000, %edi       # imm = 0x62000000
pushq $0x7
popq %rsi
callq 0x1733
movq %r15, %r14
testl %eax, %eax
je 0x1f5a
movl %r12d, %edi
shll $0x1b, %edi
addl $0xa0000000, %edi       # imm = 0xA0000000
pushq $0x4
popq %rsi
callq 0x1733
movl %eax, %ebp
jmp 0x1f5c
cmpl $-0x8, %r13d
jb 0x2265
xorl %ebp, %ebp
xorl %edi, %edi
movl %esi, %ebx
callq 0x1733
testl %eax, %eax
je 0x219b
movl %r13d, %edi
shll $0x1d, %edi
jmp 0x1e3f
cmpl $-0x20, %r13d
jb 0x1e8e
movl $0x38000000, %edi       # imm = 0x38000000
pushq $0x5
popq %rbx
movl %ebx, %esi
callq 0x1733
testl %eax, %eax
je 0x2096
movl %r13d, %edi
shll $0x1b, %edi
movl %ebx, %esi
callq 0x1733
jmp 0x208f
leal -0x3(%r12), %eax
cmpl $0xefc, %eax            # imm = 0xEFC
ja 0x2265
cmpl $0xffff0000, %r13d      # imm = 0xFFFF0000
jb 0x2265
cmpl $0xfffffdff, %r13d      # imm = 0xFFFFFDFF
movq %r15, 0x8(%rsp)
ja 0x1ecb
movl %r13d, %eax
negl %eax
movl $0x400, %ecx            # imm = 0x400
movl %ebp, %r15d
cmpl %eax, %ecx
jae 0x1edc
addl %ecx, %ecx
incl %r15d
jmp 0x1e83
leal 0x100(%r13), %eax
cmpl $0xdf, %eax
ja 0x1f97
movl $0x30000000, %edi       # imm = 0x30000000
jmp 0x2078
leal 0x4f(%r13), %eax
cmpl $0x3e, %eax
ja 0x2265
testb $0x1, %r13b
jne 0x2013
movl $0x30000000, %edi       # imm = 0x30000000
jmp 0x2018
cmpl $0x10, %r12d
jae 0x1fbf
movl 0x4(%rsp), %r15d
jmp 0x1f34
pushq $0x1
popq %rax
movl 0x4(%rsp), %ebp
cmpl %ebp, %r15d
jbe 0x1f14
xorl %ebx, %ebx
testl %eax, %eax
je 0x1f0e
movl $0x30000000, %edi       # imm = 0x30000000
pushq $0x5
popq %rsi
callq 0x1733
testl %eax, %eax
je 0x1f0e
movl $0xfe, %edi
pushq $0x2
popq %rsi
callq 0x1678
movl %eax, %ebx
incl %ebp
movl %ebx, %eax
jmp 0x1ee3
movl 0x4(%rsp), %ecx
cmpl %r15d, %ecx
cmoval %ecx, %r15d
cmpl $0x10, %r12d
jge 0x1fcd
testl %eax, %eax
pushq $0x2
popq %rbp
je 0x20de
xorl %edi, %edi
pushq $0x1
popq %rsi
callq 0x1733
cmpl $0x3, %r12d
jne 0x204c
testl %eax, %eax
je 0x20da
movl $0x80000000, %edi       # imm = 0x80000000
jmp 0x211d
xorl %ebp, %ebp
xorl %r15d, %r15d
testl %ebp, %ebp
je 0x1f8a
cmpq %r12, %r15
jae 0x1f8a
leaq 0x83b1(%rip), %rax      # 0xa320
movq 0x40(%rax), %rax
leal (%rbx,%r15), %ecx
movzbl (%rax,%rcx), %edi
pushq $0x2
popq %rsi
callq 0x1678
movl %eax, %ebp
incq %r15
jmp 0x1f5f
movq %r14, %r15
movl 0x18(%rsp), %r14d
jmp 0x219b
movl %r13d, %eax
andl $0xffffff00, %eax       # imm = 0xFFFFFF00
cmpl $0xfffffd00, %eax       # imm = 0xFFFFFD00
je 0x2073
cmpl $0xfffffe00, %eax       # imm = 0xFFFFFE00
jne 0x2265
movl $0x28000000, %edi       # imm = 0x28000000
jmp 0x2078
cmpl $0x80, %r12d
jb 0x1fea
jmp 0x20a6
cmpl $0x80, %r12d
pushq $0x2
popq %rbp
jae 0x209d
testl %eax, %eax
je 0x20da
movl %r15d, 0x4(%rsp)
movl $0x60000000, %edi       # imm = 0x60000000
pushq $0x7
popq %rbx
movl %ebx, %esi
callq 0x1733
testl %eax, %eax
je 0x20ed
movl %r12d, %edi
shll $0x19, %edi
movl %ebx, %esi
callq 0x1733
jmp 0x20d6
movl $0x48000000, %edi       # imm = 0x48000000
pushq $0x5
popq %rsi
callq 0x1733
testl %eax, %eax
je 0x2096
leal 0xf(%r13), %eax
shrb %al
xorb $-0x7f, %al
movzbl %al, %edi
movl %ebp, %esi
callq 0x1678
testl %eax, %eax
je 0x2096
leaq 0x82df(%rip), %rax      # 0xa320
movq 0x40(%rax), %rax
movzbl 0x1(%rbx,%rax), %edi
jmp 0x2088
testl %eax, %eax
pushq $0x3
popq %rcx
je 0x20f6
movl %r12d, %eax
xorl %edx, %edx
divl %ecx
leal (%rax,%rax), %esi
pushq $-0x1
popq %rdi
callq 0x1733
testl %eax, %eax
setne %al
jmp 0x20f8
movl $0x20000000, %edi       # imm = 0x20000000
pushq $0x5
popq %rsi
callq 0x1733
testl %eax, %eax
je 0x2096
movzbl %r13b, %edi
movl %ebp, %esi
callq 0x1678
movl %eax, %ebp
jmp 0x219b
xorl %ebp, %ebp
jmp 0x219b
testl %eax, %eax
je 0x20da
movl %r15d, 0x4(%rsp)
movl $0x60000000, %edi       # imm = 0x60000000
pushq $0x7
popq %rsi
callq 0x1733
xorl %ebx, %ebx
testl %eax, %eax
je 0x20ef
movl %r12d, %edi
shll $0x11, %edi
pushq $0x7
popq %rsi
callq 0x1733
testl %eax, %eax
je 0x20ef
movzbl %r12b, %edi
movl %ebp, %esi
callq 0x1678
movl %eax, %ebx
jmp 0x20ef
xorl %ebx, %ebx
jmp 0x2126
xorl %eax, %eax
movl $0x0, %ebx
cmpl $0x3, %r12d
jne 0x20f8
jmp 0x2126
xorl %ebx, %ebx
movl 0x4(%rsp), %r15d
jmp 0x2126
xorl %eax, %eax
cmpq $0xf, %r12
sete %cl
andb %al, %cl
movzbl %cl, %ebx
cmpl $0xf, %r12d
je 0x2126
testb %al, %al
je 0x2126
movl %r12d, %eax
xorl %edx, %edx
pushq $0x3
popq %rcx
divl %ecx
movl %edx, %edi
shll $0x1e, %edi
movl %ebp, %esi
callq 0x1733
movl %eax, %ebx
xorl %ebp, %ebp
cmpl $-0x20, %r13d
jl 0x2153
testl %ebx, %ebx
je 0x2191
movl $0x80000000, %edi       # imm = 0x80000000
pushq $0x2
popq %rsi
callq 0x1733
testl %eax, %eax
je 0x2191
movl %r13d, %edi
shll $0x1b, %edi
pushq $0x5
popq %rsi
callq 0x1733
jmp 0x218f
cmpl $0xffffff00, %r13d      # imm = 0xFFFFFF00
jb 0x2167
testl %ebx, %ebx
je 0x2191
movl $0x40000000, %edi       # imm = 0x40000000
jmp 0x2176
cmpl $0xfffffe00, %r13d      # imm = 0xFFFFFE00
jb 0x21bb
testl %ebx, %ebx
je 0x2191
xorl %edi, %edi
pushq $0x2
popq %rbx
movl %ebx, %esi
callq 0x1733
testl %eax, %eax
je 0x2191
movzbl %r13b, %edi
movl %ebx, %esi
callq 0x1678
movl %eax, %ebp
movl %r15d, 0x4(%rsp)
movq 0x8(%rsp), %r15
cmpl %r13d, %r15d
cmovgel %r13d, %r15d
movl %r12d, %eax
negl %eax
cmovsl %r12d, %eax
movl 0x1c(%rsp), %ecx
addl %eax, %ecx
movq 0x20(%rsp), %r13
jmp 0x1cec
testl %ebx, %ebx
je 0x2191
movl $0xc0000000, %edi       # imm = 0xC0000000
pushq $0x2
popq %rsi
callq 0x1733
testl %eax, %eax
je 0x2191
movb $0x18, %cl
subb %r15b, %cl
movl %r13d, %edi
shll %cl, %edi
movl %r15d, %esi
callq 0x1733
testl %eax, %eax
je 0x2191
movzbl %r13b, %edi
pushq $0x2
popq %rsi
jmp 0x218a
leaq 0x3111(%rip), %rdi      # 0x5307
jmp 0x224d
xorl %ebx, %ebx
testl %ebp, %ebp
je 0x2254
pushq $0xe
popq %rsi
movl $0x603c0000, %edi       # imm = 0x603C0000
callq 0x1733
testl %eax, %eax
je 0x2254
xorl %ebx, %ebx
xorl %edi, %edi
xorl %esi, %esi
callq 0x1733
testl %eax, %eax
je 0x2254
xorl %ebx, %ebx
xorl %edi, %edi
xorl %esi, %esi
callq 0x156d
testl %eax, %eax
je 0x2254
negl %r15d
leaq 0x2e13(%rip), %rdi      # 0x504a
movl %r15d, %esi
xorl %eax, %eax
callq 0x1040
pushq $0x1
popq %rbx
jmp 0x2254
leaq 0x30e2(%rip), %rdi      # 0x532f
callq 0x1110
xorl %ebx, %ebx
movl %ebx, %eax
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x2e53(%rip), %rdi      # 0x50bf
xorl %ebx, %ebx
movl %r12d, %esi
movl %r13d, %edx
xorl %eax, %eax
callq 0x1040
jmp 0x2254