// File: /workspace/github_cpp_makefile_star2_O1/ksherlock[P]wdc-utils/link.cpp
// Function: to_omf(expression const&, omf::segment&)
void to_omf(const expression &e, omf::segment &seg) {
	if (e.stack.empty() || e.size == 0) {
		expr_error(false, e, "Expression empty");
		return;
	}

	if (e.size < 1 || e.size > 4) {
		expr_error(true, e, "Expression size must be 1-4 bytes");
	}


	if (e.stack.size() == 1) {
		auto &a = e.stack[0];

		uint32_t value = a.value;

		if (e.relative) {
			if (a.tag == OP_VAL || a.tag == OP_LOC) {

				int tmp = (int)value - (int)e.offset - (int)e.size;
				bool ok = false;

				if (e.size >= 2 && in_range(tmp, -32768, 32767)) ok = true;
				if (e.size == 1 && in_range(tmp, -128, 127)) ok = true;

				if (!ok) {
					expr_error(true, e, "Relative branch out of range");
					return;					
				}

				for (int i = 0; i < e.size; ++i, tmp >>= 8)
					seg.data[e.offset + i] = tmp & 0xff;

				return;
			}

			expr_error(true, e, "Relative expression too complex");
			return;
		}


		if (a.tag == OP_VAL) {
			for (int i = 0; i < e.size; ++i, value >>= 8)
				seg.data[e.offset + i] = value & 0xff;
			return;
		}

		if (a.tag == OP_LOC) {
			auto &loc = a;

			if (loc.section == 0) {
				expr_error(true, e, "Invalid segment");
				return;
			}

			if (loc.section == seg.segnum) {
				omf::reloc r;
				r.size = e.size;
				r.offset = e.offset;
				r.value = value;

				seg.relocs.emplace_back(r);
			} else {
				omf::interseg r;
				r.size = e.size;
				r.offset = e.offset;
				r.segment = loc.section;
				r.segment_offset = loc.value;

				seg.intersegs.emplace_back(r);

				// if generating super, store 
			}
			return;
		}

		// error handled below.
	}



	if (e.stack.size() == 3) {
		auto &loc = e.stack[0];
		auto &shift = e.stack[1];
		auto &op = e.stack[2];

		if (loc.tag == OP_LOC && shift.tag == OP_VAL && (op.tag == OP_SHL || op.tag == OP_SHR)) {


			if (shift.value > 24) {
				expr_error(false, e, "Shift too large");
				// data is already pre-zeroed.
				return;
			}

			if (loc.section == 0) {
				expr_error(true, e, "Invalid segment");
				return;
			}

			uint32_t value = loc.value;
			uint8_t shift_value = shift.value;
			if (op.tag == OP_SHR) {
				value >>= shift_value;
				shift_value = -shift_value;
			} else {
				value <<= shift_value;
			}

			if (loc.section == seg.segnum) {
				omf::reloc r;
				r.size = e.size;
				r.offset = e.offset;
				r.value = loc.value;
				r.shift = shift_value;

				#if 0
				// also store value in data
				for (int i = 0; i < e.size; ++i, value >>= 8)
					seg.data[e.offset + i] = value & 0xff;
				#endif

				seg.relocs.emplace_back(r);
			} else {
				omf::interseg r;
				r.size = e.size;
				r.offset = e.offset;
				r.segment = loc.section;
				r.segment_offset = loc.value;
				r.shift = shift_value;

				seg.intersegs.emplace_back(r);
			}
			return;
		}
	}


	expr_error(true, e, "Expression too complex");
	// should also pretty-print the expression.
	return;

}

// Assembly:
pushq %r14
pushq %rbx
subq $0x18, %rsp
movq %rdi, %r14
movq 0x10(%rdi), %rax
cmpq 0x18(%rdi), %rax
je 0x4496
movb 0x8(%r14), %al
testb %al, %al
je 0x4496
movq %rsi, %rbx
cmpb $0x5, %al
jb 0x442a
leaq 0xaf0d(%rip), %rdx      # 0xf32a
movl $0x1, %edi
movq %r14, %rsi
callq 0x6108
movq 0x10(%r14), %rcx
movq 0x18(%r14), %rax
subq %rcx, %rax
cmpq $0xc, %rax
jne 0x44df
movl (%rcx), %edx
movl 0x4(%rcx), %eax
cmpb $0x0, 0x9(%r14)
je 0x44a4
andl $-0x2, %edx
cmpl $0x2, %edx
jne 0x4526
movzbl 0x8(%r14), %edx
movl %edx, %esi
xorl $0x1, %esi
cmpl $0x2, %edx
setae %cl
addl 0x4(%r14), %edx
subl %edx, %eax
movswl %ax, %edx
cmpl %eax, %edx
sete %dl
movsbl %al, %edi
xorl %eax, %edi
orl %esi, %edi
je 0x4541
andb %dl, %cl
jne 0x4541
leaq 0xaebb(%rip), %rdx      # 0xf34c
jmp 0x452d
leaq 0xae7c(%rip), %rdx      # 0xf319
xorl %edi, %edi
jmp 0x4532
cmpl $0x3, %edx
je 0x456e
cmpl $0x2, %edx
jne 0x44df
cmpb $0x0, 0x8(%r14)
je 0x4693
xorl %ecx, %ecx
movl 0x4(%r14), %edx
addl %ecx, %edx
movq 0x50(%rbx), %rsi
movb %al, (%rsi,%rdx)
incl %ecx
shrl $0x8, %eax
movzbl 0x8(%r14), %edx
cmpl %edx, %ecx
jb 0x44bf
jmp 0x4693
movq 0x10(%r14), %rax
movq 0x18(%r14), %rcx
subq %rax, %rcx
cmpq $0x24, %rcx
jne 0x451d
cmpl $0x3, (%rax)
jne 0x451d
cmpl $0x2, 0xc(%rax)
jne 0x451d
movl 0x18(%rax), %ecx
movl %ecx, %edx
andl $-0x2, %edx
cmpl $0x18, %edx
jne 0x451d
movl 0x10(%rax), %edx
cmpl $0x19, %edx
jb 0x45a8
leaq 0xae7e(%rip), %rdx      # 0xf399
jmp 0x449d
leaq 0xae85(%rip), %rdx      # 0xf3a9
jmp 0x452d
leaq 0xae3c(%rip), %rdx      # 0xf369
movl $0x1, %edi
movq %r14, %rsi
addq $0x18, %rsp
popq %rbx
popq %r14
jmp 0x6108
cmpb $0x0, 0x8(%r14)
je 0x4693
xorl %ecx, %ecx
movl 0x4(%r14), %edx
addl %ecx, %edx
movq 0x50(%rbx), %rsi
movb %al, (%rsi,%rdx)
incl %ecx
sarl $0x8, %eax
movzbl 0x8(%r14), %edx
cmpl %edx, %ecx
jb 0x454e
jmp 0x4693
movl 0x8(%rcx), %edx
testl %edx, %edx
je 0x4602
movzwl (%rbx), %esi
cmpl %esi, %edx
jne 0x460e
leaq 0x8(%rsp), %rsi
movw $0x0, (%rsi)
movq $0x0, 0x4(%rsi)
movb 0x8(%r14), %cl
movb %cl, (%rsi)
movl 0x4(%r14), %ecx
movl %ecx, 0x4(%rsi)
movl %eax, 0x8(%rsi)
jmp 0x45f1
movl 0x8(%rax), %esi
testl %esi, %esi
je 0x4602
movl %edx, %edi
negb %dil
cmpl $0x18, %ecx
movzbl %dil, %ecx
cmovnel %edx, %ecx
movzwl (%rbx), %edx
cmpl %edx, %esi
jne 0x464a
leaq 0x8(%rsp), %rsi
movw $0x0, (%rsi)
movq $0x0, 0x4(%rsi)
movb 0x8(%r14), %dl
movb %dl, (%rsi)
movl 0x4(%r14), %edx
movl %edx, 0x4(%rsi)
movl 0x4(%rax), %eax
movl %eax, 0x8(%rsi)
movb %cl, 0x1(%rsi)
subq $-0x80, %rbx
movq %rbx, %rdi
callq 0x6f46
jmp 0x4693
leaq 0xad80(%rip), %rdx      # 0xf389
jmp 0x452d
leaq 0x8(%rsp), %rsi
movw $0x0, (%rsi)
movabsq $0x100000000, %rax      # imm = 0x100000000
movq %rax, 0x4(%rsi)
movl $0x0, 0xc(%rsi)
movb 0x8(%r14), %al
movb %al, (%rsi)
movl 0x4(%r14), %eax
movl %eax, 0x4(%rsi)
movzwl 0x8(%rcx), %eax
movw %ax, 0xa(%rsi)
movl 0x4(%rcx), %eax
movl %eax, 0xc(%rsi)
jmp 0x4687
leaq 0x8(%rsp), %rsi
movw $0x0, (%rsi)
movabsq $0x100000000, %rdx      # imm = 0x100000000
movq %rdx, 0x4(%rsi)
movl $0x0, 0xc(%rsi)
movb 0x8(%r14), %dl
movb %dl, (%rsi)
movl 0x4(%r14), %edx
movl %edx, 0x4(%rsi)
movzwl 0x8(%rax), %edx
movw %dx, 0xa(%rsi)
movl 0x4(%rax), %eax
movl %eax, 0xc(%rsi)
movb %cl, 0x1(%rsi)
addq $0x68, %rbx
movq %rbx, %rdi
callq 0x6f7c
addq $0x18, %rsp
popq %rbx
popq %r14
retq