// File: /workspace/github_c_makefile_star2_O2/lmcilroy[P]lzm/lzmdecode.c
// Function: lzm_decode
unsigned int
lzm_decode(
    const struct lzm_state * const state,
    const unsigned char * const buffer_in,
    const unsigned int size_in,
    unsigned char * const buffer_out,
    unsigned int * const size_out)
{
	const unsigned char * const end = buffer_in + size_in;
	const unsigned char * const match_end = end - 5;
	const unsigned char *curr_in = (const unsigned char *) buffer_in;
	unsigned char *curr_out = (unsigned char *) buffer_out;
	const unsigned char * const out_limit = buffer_out + *size_out;
	const unsigned char *out_limit_fast_path;
	unsigned char *match;
	unsigned char *mend;
	unsigned long int c;
	unsigned int llen;
	unsigned int mlen;
	unsigned int off = 1;
	unsigned char op;

	(void)state;

	if (buffer_in == NULL || buffer_out == NULL)
		return EINVAL;

	out_limit_fast_path = (*size_out < (14 + 14 + MIN_MATCH)) ? NULL :
		out_limit - (14 + 14 + MIN_MATCH);

	while (likely(curr_in <= match_end)) {
		op = *curr_in++;
		llen = op >> 4;
		mlen = (op & 15) + MIN_MATCH;

		curr_in = decode_offset(curr_in, &off);

		if (likely(llen < 15 && (curr_in + 16) <= end &&
		    curr_out <= out_limit_fast_path)) {
			LOG("L %d\n", llen);
			memcpy(curr_out, curr_in, 16);
			curr_out += llen;
			curr_in += llen;
			if (unlikely(off > (curr_out - buffer_out)))
				return EIO;
			if (likely(mlen < (15 + MIN_MATCH) &&
			    likely(((off >= mlen) | (off >= 8))))) {
				LOG("M %d %d\n", mlen, off);
				match = curr_out - off;
				memcpy(curr_out, match, 8);
				memcpy(curr_out+8, match+8, 8);
				memcpy(curr_out+16, match+16, 2);
				curr_out += mlen;
				continue;
			}
			goto match;
		}

		if (likely(llen > 0)) {
			if (unlikely(llen == 15)) {
				if (unlikely(curr_in >= end - 15))
					return EIO;

				curr_in = decode_length(curr_in, &llen);
				llen += 15;
			}
			LOG("L %d\n", llen);
			if (unlikely((curr_in + llen) > end))
				return EIO;
			if (unlikely((curr_out + llen) > out_limit))
				return EOVERFLOW;
			memcpy(curr_out, curr_in, llen);
			curr_in += llen;
			curr_out += llen;
		}

		if (unlikely(off > (curr_out - buffer_out)))
			return EIO;

 match:
		if (unlikely(off == 0))
			break;

		if (likely(mlen < (15 + MIN_MATCH) && off >= mlen &&
		    (curr_out + (14 + MIN_MATCH)) <= out_limit)) {
			LOG("M %d %d\n", mlen, off);
			match = curr_out - off;
			memcpy(curr_out, match, 8);
			memcpy(curr_out+8, match+8, 8);
			memcpy(curr_out+16, match+16, 2);
			curr_out += mlen;
			continue;
		}

		if (likely(mlen == (15 + MIN_MATCH))) {
			if (unlikely(curr_in >= match_end))
				return EIO;

			curr_in = decode_length(curr_in, &mlen);
			mlen += 15 + MIN_MATCH;
		}

		LOG("M %d %d\n", mlen, off);
		if (unlikely((curr_out + mlen) > out_limit))
			return EOVERFLOW;

		match = curr_out - off;
		mend = curr_out + mlen;

		if (likely(mlen <= off)) {
			memcpy(curr_out, match, mlen);
			curr_out += mlen;
			continue;
		}

		if (off == 1) {
			c = *match;
			*curr_out++ = c;
			*curr_out++ = c;
			*curr_out++ = c;
			*curr_out++ = c;
			while (curr_out < mend)
				*curr_out++ = c;
			continue;
		}

		if (off == 2) {
			c = readmem16(match);
			writemem16(curr_out, c);
			curr_out += 2;
			writemem16(curr_out, c);
			curr_out += 2;
			while (curr_out < mend) {
				writemem16(curr_out, c);
				curr_out += 2;
				writemem16(curr_out, c);
				curr_out += 2;
			}
			curr_out = mend;
			continue;
		}

		if (off == 3) {
			unsigned char c1, c2, c3;
			c1 = *match;
			c2 = *(match+1);
			c3 = *(match+2);
			*curr_out++ = c1;
			*curr_out++ = c2;
			*curr_out++ = c3;
			*curr_out++ = c1;
			*curr_out++ = c2;
			*curr_out++ = c3;
			while (curr_out < mend) {
				*curr_out++ = c1;
				*curr_out++ = c2;
				*curr_out++ = c3;
			}
			curr_out = mend;
		}

		if (off == 4) {
			c = readmem32(match);
			writemem32(curr_out, c);
			curr_out += off;
			writemem32(curr_out, c);
			curr_out += off;
			while (curr_out < mend) {
				writemem32(curr_out, c);
				curr_out += off;
				writemem32(curr_out, c);
				curr_out += off;
			}
			curr_out = mend;
			continue;
		}

		if (off <= 8) {
			c = readmem64(match);
			writemem64(curr_out, c);
			curr_out += off;
			while (curr_out < mend) {
				writemem64(curr_out, c);
				curr_out += off;
			}
			curr_out = mend;
			continue;
		}

		memcpy(curr_out, match, 4);
		match += 4;
		curr_out += 4;
		while (curr_out < mend) {
			memcpy(curr_out, match, 8);
			match += 8;
			curr_out += 8;
		}
		curr_out = mend;
	}

	*size_out = curr_out - buffer_out;

	/* Finished without seeing end of stream? */
	if (off != 0)
		return EIO;

	return 0;
}

// Assembly:
movq %rcx, %rdi
testq %rsi, %rsi
sete %al
testq %rcx, %rcx
sete %cl
orb %al, %cl
je 0x3d55
pushq $0x16
popq %rax
retq
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x58, %rsp
movq %rsi, %r13
movl %edx, %eax
leaq (%rsi,%rax), %r9
leaq -0x5(%rsi,%rax), %r10
movq %r8, 0x30(%rsp)
movl (%r8), %eax
movq %rax, %r8
addq %rdi, %r8
leaq -0x20(%r8), %rcx
xorl %r11d, %r11d
cmpl $0x20, %eax
cmovaeq %rcx, %r11
leaq -0xf(%r9), %rax
movq %rax, 0x40(%rsp)
pushq $0x1
popq %r15
movq %rdi, %r14
movq %r10, 0x20(%rsp)
movq %r11, 0x18(%rsp)
movq %rdi, 0x48(%rsp)
movq %r8, 0x38(%rsp)
cmpq %r10, %r13
ja 0x40fe
movzbl (%r13), %ebp
movl %ebp, %eax
shrl $0x4, %eax
movl %eax, 0x2c(%rsp)
andl $0xf, %ebp
leaq 0x4(%rbp), %rbx
movl %ebx, 0xc(%rsp)
movl 0x1(%r13), %r15d
bsfl %r15d, %edx
leal 0x1(%rdx), %ecx
leaq 0x1a5b(%rip), %rsi      # 0x5840
andl (%rsi,%rcx,4), %r15d
shrq %cl, %r15
leaq (%rdx,%r13), %rsi
addq $0x2, %rsi
movl %r15d, %r12d
cmpl $0xf, %eax
je 0x3e79
leaq (%rdx,%r13), %rcx
addq $0x12, %rcx
cmpq %r9, %rcx
ja 0x3e79
cmpq %r11, %r14
ja 0x3e79
movups (%rsi), %xmm0
movups %xmm0, (%r14)
addq %rax, %r14
movq %r14, %rcx
subq %rdi, %rcx
cmpq %r12, %rcx
jl 0x40f9
addq %rax, %rsi
cmpl $0xf, %ebp
je 0x3ee2
cmpl %ebx, %r15d
setb %al
cmpl $0x8, %r15d
setb %cl
testb %cl, %al
jne 0x3ee2
movq %r14, %rax
subq %r12, %rax
movq (%rax), %rcx
movq %rcx, (%r14)
movq 0x8(%rax), %rax
movq %rax, 0x8(%r14)
negq %r12
movzwl 0x10(%r14,%r12), %eax
movw %ax, 0x10(%r14)
movl 0xc(%rsp), %eax
addq %rax, %r14
movq %rsi, %r13
jmp 0x3db1
testl %eax, %eax
je 0x3f9c
cmpl $0xf, %eax
je 0x3fa4
movl %eax, %edx
leaq (%rsi,%rdx), %r13
cmpq %r9, %r13
ja 0x40f9
leaq (%r14,%rdx), %rax
movq %rax, 0x50(%rsp)
cmpq %r8, %rax
ja 0x412f
movq %r14, %rdi
movq %r9, %r14
callq 0x11b0
movq 0x18(%rsp), %r11
movq 0x38(%rsp), %r8
movq 0x20(%rsp), %r10
movq %r14, %r9
movq 0x48(%rsp), %rdi
movq 0x50(%rsp), %r14
movq %r14, %rax
subq %rdi, %rax
cmpq %r12, %rax
jge 0x3ee5
jmp 0x40f9
movq %rsi, %r13
testl %r15d, %r15d
je 0x4122
cmpl $0xf, %ebp
je 0x3f29
cmpl %ebx, %r15d
jb 0x3f29
leaq 0x12(%r14), %rax
cmpq %r8, %rax
ja 0x3f29
movq %r14, %rax
subq %r12, %rax
movq (%rax), %rcx
movq %rcx, (%r14)
movq 0x8(%rax), %rcx
movq %rcx, 0x8(%r14)
movzwl 0x10(%rax), %eax
movw %ax, 0x10(%r14)
addq %r14, %rbx
movq %rbx, %r14
jmp 0x3db1
cmpl $0x13, %ebx
movq %r9, 0x10(%rsp)
jne 0x3fde
cmpq %r10, %r13
jae 0x40f9
movq %r8, %rbp
movq %rdi, %r12
movq %r13, %rdi
leaq 0xc(%rsp), %rsi
callq 0x4133
movq %rax, %r13
movl 0xc(%rsp), %ebx
addl $0x13, %ebx
movl %ebx, 0xc(%rsp)
movl %ebx, %edx
movq %r14, %rdi
addq %rdx, %r14
cmpq %rbp, %r14
ja 0x412f
movq %rdi, %rsi
subq %r15, %rsi
cmpl %r15d, %edx
ja 0x3fe9
callq 0x11b0
movq %r12, %rdi
movq 0x10(%rsp), %r9
movq 0x20(%rsp), %r10
movq %rbp, %r8
movq 0x18(%rsp), %r11
jmp 0x3db1
movq %rsi, %r13
jmp 0x3ed2
movq %r9, 0x10(%rsp)
cmpq 0x40(%rsp), %rsi
jae 0x40f9
movq %rsi, %rdi
leaq 0x2c(%rsp), %rsi
callq 0x4133
movq %rax, %rsi
movl 0x2c(%rsp), %eax
addl $0xf, %eax
movl %eax, 0x2c(%rsp)
movq 0x10(%rsp), %r9
movq 0x38(%rsp), %r8
jmp 0x3e8a
movq %r8, %rbp
movq %rdi, %r12
jmp 0x3f61
cmpl $0x3, %r15d
je 0x4028
cmpl $0x2, %r15d
je 0x405f
cmpl $0x1, %r15d
jne 0x408e
movb (%rsi), %al
movb %al, (%rdi)
movb %al, 0x1(%rdi)
movb %al, 0x2(%rdi)
addq $0x3, %rdi
movq %rdi, %rcx
movq %rcx, %rdx
movb %al, (%rcx)
incq %rdx
movq %rdx, %rcx
cmpq %r14, %rdx
jb 0x4010
movq %rcx, %r14
jmp 0x3f82
movb (%rsi), %al
movb 0x1(%rsi), %cl
movb 0x2(%rsi), %dl
movb %al, (%rdi)
movb %cl, 0x1(%rdi)
movb %dl, 0x2(%rdi)
movb %al, 0x3(%rdi)
movb %cl, 0x4(%rdi)
addq $0x5, %rdi
movq %rdi, %r8
movb %dl, (%rdi)
incq %r8
cmpq %r14, %r8
jae 0x408b
movq %r8, %rdi
movb %al, (%r8)
movb %cl, 0x1(%r8)
addq $0x2, %rdi
jmp 0x4042
movzwl (%rsi), %eax
movw %ax, (%rdi)
addq $0x2, %rdi
movq %rdi, %rcx
movq %rcx, %rdx
movw %ax, (%rcx)
addq $0x2, %rdx
cmpq %r14, %rdx
jae 0x3f82
movq %rdx, %rcx
movw %ax, (%rdx)
addq $0x2, %rcx
jmp 0x406c
movq %r14, %rdi
cmpl $0x4, %r15d
jne 0x40b2
movl (%rsi), %eax
movq %rdi, %rcx
movl %eax, (%rdi)
movl %eax, (%rdi,%r15)
addq %r15, %rcx
addq %r15, %rcx
movq %rcx, %rdi
cmpq %r14, %rcx
jb 0x4096
jmp 0x3f82
cmpl $0x8, %r15d
ja 0x40d1
movq (%rsi), %rax
movq %rdi, %rcx
movq %rax, (%rdi)
addq %r15, %rcx
movq %rcx, %rdi
cmpq %r14, %rcx
jb 0x40bb
jmp 0x3f82
movl (%rsi), %eax
movl %eax, (%rdi)
addq $0x4, %rsi
addq $0x4, %rdi
movq %rdi, %rcx
cmpq %r14, %rcx
jae 0x3f82
movq (%rsi), %rax
movq %rax, (%rcx)
addq $0x8, %rsi
addq $0x8, %rcx
jmp 0x40e0
pushq $0x5
popq %rax
jmp 0x4113
subl %edi, %r14d
movq 0x30(%rsp), %rax
movl %r14d, (%rax)
testl %r15d, %r15d
pushq $0x5
popq %rax
jne 0x4113
xorl %eax, %eax
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
subl %edi, %r14d
movq 0x30(%rsp), %rax
movl %r14d, (%rax)
jmp 0x4111
pushq $0x4b
jmp 0x40fb