// File: ksherlock[P]wdc-utils/expression.cpp
// Function: binary_op(unsigned int, std::vector<expr, std::allocator<expr>>&)
bool binary_op(unsigned op, std::vector<expr> &v) {
	if (v.size() >= 2) {
		expr &a = v[v.size() - 2];
		expr &b = v[v.size() - 1];

		if (a.tag == OP_VAL && b.tag == OP_VAL) {
			uint32_t value = 0;
			switch(op) {
			case OP_EXP: value = power(a.value, b.value); break;
			case OP_MUL: value = a.value * b.value; break;
			case OP_DIV: value = a.value / b.value; break;
			case OP_MOD: value = a.value % b.value; break;
			case OP_SHR: value = a.value >> b.value; break;
			case OP_SHL: value = a.value << b.value; break;
			case OP_ADD: value = a.value + b.value; break;
			case OP_SUB: value = a.value - b.value; break;
			case OP_AND: value = a.value & b.value; break;
			case OP_OR: value = a.value | b.value; break;
			case OP_XOR: value = a.value ^ b.value; break;
			case OP_EQ: value = a.value == b.value; break;
			case OP_GT: value = (int32_t)a.value > (int32_t)b.value; break;
			case OP_LT: value = (int32_t)a.value < (int32_t)b.value; break;
			case OP_UGT: value = a.value > b.value; break;
			case OP_ULT: value = a.value < b.value; break;
			default:
				errx(EX_SOFTWARE, "Unsupported binary op %02x", a.tag);
			}
			v.pop_back();
			v.back().value = value;
			return true;
		}
		if (a.tag == OP_VAL && b.tag == OP_LOC) {
			switch(op) {
				case OP_ADD: {
					// constant + symbol
					expr tmp = b;
					tmp.value = a.value + b.value;
					v.pop_back();
					v.pop_back();
					v.emplace_back(tmp);
					return true; 
				}
				#if 0
				case OP_SUB: {
					// constant - symbol .. does this even make sense?
					expr tmp = b;
					tmp.value = a.value - b.value;
					v.pop_back();
					v.pop_back();
					v.emplace_back(tmp);
					return true; 
				}
				#endif
			}
		}
		// optimization... regardless of where it's located, shifting > 24 bits will result in 0...
		if (a.tag == OP_LOC && b.tag == OP_VAL) {
			switch(op) {
				case OP_ADD: {
					a.value += b.value;
					v.pop_back();
					return true;
				}
				case OP_SUB: {
					a.value -= b.value;
					v.pop_back();
					return true;
				}
			}
		}

		if (a.tag == OP_LOC && b.tag == OP_LOC && a.section == b.section) {
			uint32_t value = 0;
			bool rv = false;
			switch (op) {
				case OP_SUB:
					// end - start
					value = a.value - b.value;
					rv = true; break;
				case OP_EQ:
					value = a.value == b.value;
					rv = true; break;
				case OP_GT:
				case OP_UGT:
					value = a.value > b.value;
					rv = true; break;
				case OP_LT:
				case OP_ULT:
					value = a.value < b.value;
					rv = true; break;
			}
			if (rv) {
				v.pop_back();
				v.pop_back();
				v.emplace_back(OP_VAL, value);
				return true;
			}
		}


	}
	v.emplace_back(op);
	return false;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x70, %rsp
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x10(%rbp), %rdi
callq 0xa020
cmpq $0x2, %rax
jb 0x22099
movq -0x10(%rbp), %rax
movq %rax, -0x50(%rbp)
movq -0x10(%rbp), %rdi
callq 0xa020
movq -0x50(%rbp), %rdi
movq %rax, %rsi
subq $0x2, %rsi
callq 0x22b00
movq %rax, -0x18(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x48(%rbp)
movq -0x10(%rbp), %rdi
callq 0xa020
movq -0x48(%rbp), %rdi
movq %rax, %rsi
subq $0x1, %rsi
callq 0x22b00
movq %rax, -0x20(%rbp)
movq -0x18(%rbp), %rax
cmpl $0x2, (%rax)
jne 0x21eb0
movq -0x20(%rbp), %rax
cmpl $0x2, (%rax)
jne 0x21eb0
movl $0x0, -0x24(%rbp)
movl -0x8(%rbp), %eax
addl $-0x14, %eax
movl %eax, %ecx
movq %rcx, -0x58(%rbp)
subl $0xf, %eax
ja 0x21e70
movq -0x58(%rbp), %rax
leaq 0x9e13(%rip), %rcx      # 0x2baf0
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x18(%rbp), %rax
movl 0x4(%rax), %edi
movq -0x20(%rbp), %rax
movl 0x4(%rax), %esi
callq 0x21b00
movl %eax, -0x24(%rbp)
jmp 0x21e89
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
imull 0x4(%rcx), %eax
movl %eax, -0x24(%rbp)
jmp 0x21e89
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
xorl %edx, %edx
divl 0x4(%rcx)
movl %eax, -0x24(%rbp)
jmp 0x21e89
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
xorl %edx, %edx
divl 0x4(%rcx)
movl %edx, -0x24(%rbp)
jmp 0x21e89
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
movl 0x4(%rcx), %ecx
shrl %cl, %eax
movl %eax, -0x24(%rbp)
jmp 0x21e89
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
movl 0x4(%rcx), %ecx
shll %cl, %eax
movl %eax, -0x24(%rbp)
jmp 0x21e89
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
addl 0x4(%rcx), %eax
movl %eax, -0x24(%rbp)
jmp 0x21e89
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
subl 0x4(%rcx), %eax
movl %eax, -0x24(%rbp)
jmp 0x21e89
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
andl 0x4(%rcx), %eax
movl %eax, -0x24(%rbp)
jmp 0x21e89
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
orl 0x4(%rcx), %eax
movl %eax, -0x24(%rbp)
jmp 0x21e89
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
xorl 0x4(%rcx), %eax
movl %eax, -0x24(%rbp)
jmp 0x21e89
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
cmpl 0x4(%rcx), %eax
sete %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x24(%rbp)
jmp 0x21e89
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
cmpl 0x4(%rcx), %eax
setg %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x24(%rbp)
jmp 0x21e89
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
cmpl 0x4(%rcx), %eax
setl %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x24(%rbp)
jmp 0x21e89
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
cmpl 0x4(%rcx), %eax
seta %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x24(%rbp)
jmp 0x21e89
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
cmpl 0x4(%rcx), %eax
setb %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x24(%rbp)
jmp 0x21e89
movq -0x18(%rbp), %rax
movl (%rax), %edx
movl $0x46, %edi
leaq 0x9cc8(%rip), %rsi      # 0x2bb4a
movb $0x0, %al
callq 0x35b0
movq -0x10(%rbp), %rdi
callq 0x22b20
movl -0x24(%rbp), %eax
movl %eax, -0x5c(%rbp)
movq -0x10(%rbp), %rdi
callq 0x183d0
movl -0x5c(%rbp), %ecx
movl %ecx, 0x4(%rax)
movb $0x1, -0x1(%rbp)
jmp 0x220aa
movq -0x18(%rbp), %rax
cmpl $0x2, (%rax)
jne 0x21f18
movq -0x20(%rbp), %rax
cmpl $0x3, (%rax)
jne 0x21f18
movl -0x8(%rbp), %eax
subl $0x1a, %eax
jne 0x21f16
jmp 0x21ecc
movq -0x20(%rbp), %rax
movq (%rax), %rcx
movq %rcx, -0x30(%rbp)
movl 0x8(%rax), %eax
movl %eax, -0x28(%rbp)
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
addl 0x4(%rcx), %eax
movl %eax, -0x2c(%rbp)
movq -0x10(%rbp), %rdi
callq 0x22b20
movq -0x10(%rbp), %rdi
callq 0x22b20
movq -0x10(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0x22b50
movb $0x1, -0x1(%rbp)
jmp 0x220aa
jmp 0x21f18
movq -0x18(%rbp), %rax
cmpl $0x3, (%rax)
jne 0x21f8b
movq -0x20(%rbp), %rax
cmpl $0x2, (%rax)
jne 0x21f8b
movl -0x8(%rbp), %eax
movl %eax, -0x60(%rbp)
subl $0x1a, %eax
je 0x21f41
jmp 0x21f37
movl -0x60(%rbp), %eax
subl $0x1b, %eax
je 0x21f64
jmp 0x21f89
movq -0x20(%rbp), %rax
movl 0x4(%rax), %ecx
movq -0x18(%rbp), %rax
addl 0x4(%rax), %ecx
movl %ecx, 0x4(%rax)
movq -0x10(%rbp), %rdi
callq 0x22b20
movb $0x1, -0x1(%rbp)
jmp 0x220aa
movq -0x20(%rbp), %rax
movl 0x4(%rax), %edx
movq -0x18(%rbp), %rax
movl 0x4(%rax), %ecx
subl %edx, %ecx
movl %ecx, 0x4(%rax)
movq -0x10(%rbp), %rdi
callq 0x22b20
movb $0x1, -0x1(%rbp)
jmp 0x220aa
jmp 0x21f8b
movq -0x18(%rbp), %rax
cmpl $0x3, (%rax)
jne 0x22097
movq -0x20(%rbp), %rax
cmpl $0x3, (%rax)
jne 0x22097
movq -0x18(%rbp), %rax
movl 0x8(%rax), %eax
movq -0x20(%rbp), %rcx
cmpl 0x8(%rcx), %eax
jne 0x22097
movl $0x0, -0x34(%rbp)
movb $0x0, -0x35(%rbp)
movl -0x8(%rbp), %eax
addl $-0x1b, %eax
movl %eax, %ecx
movq %rcx, -0x68(%rbp)
subl $0x8, %eax
ja 0x2205f
movq -0x68(%rbp), %rax
leaq 0x9ae8(%rip), %rcx      # 0x2bacc
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
subl 0x4(%rcx), %eax
movl %eax, -0x34(%rbp)
movb $0x1, -0x35(%rbp)
jmp 0x2205f
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
cmpl 0x4(%rcx), %eax
sete %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x34(%rbp)
movb $0x1, -0x35(%rbp)
jmp 0x2205f
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
cmpl 0x4(%rcx), %eax
seta %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x34(%rbp)
movb $0x1, -0x35(%rbp)
jmp 0x2205f
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x20(%rbp), %rcx
cmpl 0x4(%rcx), %eax
setb %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x34(%rbp)
movb $0x1, -0x35(%rbp)
testb $0x1, -0x35(%rbp)
je 0x22095
movq -0x10(%rbp), %rdi
callq 0x22b20
movq -0x10(%rbp), %rdi
callq 0x22b20
movq -0x10(%rbp), %rdi
movl $0x2, -0x3c(%rbp)
leaq -0x3c(%rbp), %rsi
leaq -0x34(%rbp), %rdx
callq 0x220c0
movb $0x1, -0x1(%rbp)
jmp 0x220aa
jmp 0x22097
jmp 0x22099
movq -0x10(%rbp), %rdi
leaq -0x8(%rbp), %rsi
callq 0x22a80
movb $0x0, -0x1(%rbp)
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0x70, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)