// File: /workspace/github_c_makefile_star2_O3/lucvoo[P]sparse-dev/simplify.c
// Function: simplify_select
static int simplify_select(struct instruction *insn)
{
	pseudo_t cond, src1, src2;
	struct instruction *def;

	cond = insn->src1;
	src1 = insn->src2;
	src2 = insn->src3;

	if (constant(cond))
		return replace_with_pseudo(insn, cond->value ? src1 : src2);
	if (src1 == src2)
		return replace_with_pseudo(insn, src1);

	if (constant(src1) && constant(src2)) {
		long long val1 = src1->value;
		long long val2 = src2->value;

		/* The pair 0/1 is special - replace with SETNE/SETEQ */
		if ((val1 | val2) == 1) {
			int opcode = OP_SET_EQ;
			if (val1) {
				src1 = src2;
				opcode = OP_SET_NE;
			}
			insn->opcode = opcode;
			insn->itype = insn->type;
			/* insn->src1 is already cond */
			insn->src2 = src1; /* Zero */
			return REPEAT_CSE;
		}
	}
	if (cond == src2 && is_zero(src1))			// SEL(x, 0, x) --> 0
		return replace_with_pseudo(insn, src1);
	if (cond == src1 && is_zero(src2))			// SEL(x, x, 0) --> x
		return replace_with_pseudo(insn, cond);

	switch (DEF_OPCODE(def, cond)) {
	case OP_SET_EQ:
		if (src1 == def->src1 && src2 == def->src2)
			return replace_with_pseudo(insn, src2); // SEL(x==y,x,y) --> y
		if (src2 == def->src1 && src1 == def->src2)
			return replace_with_pseudo(insn, src2); // SEL(y==x,x,y) --> y
		break;
	case OP_SET_NE:
		if (src1 == def->src1 && src2 == def->src2)
			return replace_with_pseudo(insn, src1); // SEL(x!=y,x,y) --> x
		if (src2 == def->src1 && src1 == def->src2)
			return replace_with_pseudo(insn, src1); // SEL(y!=x,x,y) --> x
		break;
	case OP_SET_LE: case OP_SET_LT:
	case OP_SET_BE: case OP_SET_B:
		if (!one_use(cond))
			break;
		// SEL(x {<,<=} y, a, b) --> SEL(x {>=,>} y, b, a)
		def->opcode = opcode_negate(def->opcode);
		return switch_pseudo(insn, &insn->src2, insn, &insn->src3);
	case OP_SET_GT:
		if (one_use(cond) && is_zero(def->src2)) {
			if (is_negate_of(src2, src1))
				// SEL(x > 0, a, -a) --> SEL(x >= 0, a, -a)
				return replace_opcode(def, OP_SET_GE);
		}
		break;
	case OP_SEL:
		if (constant(def->src2) && constant(def->src3)) {
			// Is the def of the conditional another select?
			// And if that one results in a "zero or not", use the
			// original conditional instead.
			//	SEL(SEL(x, C, 0), y, z) --> SEL(x, y, z)
			//	SEL(SEL(x, C, 0), C, 0) --> SEL(x, C, 0) == cond
			//	SEL(SEL(x, 0, C), y, z) --> SEL(x, z, y)
			//	SEL(SEL(x, C1, C2), y, z) --> y
			if (!def->src3->value) {
				if ((src1 == def->src2) && (src2 == def->src3))
					return replace_with_pseudo(insn, cond);
				return replace_pseudo(insn, &insn->cond, def->cond);
			}
			if (!def->src2->value) {
				switch_pseudo(insn, &insn->src2, insn, &insn->src3);
				return replace_pseudo(insn, &insn->cond, def->cond);
			}
			// both values must be non-zero
			return replace_with_pseudo(insn, src1);
		}
	case OP_AND:
		if (is_pow2(def->src2) && is_pow2(src1) && is_zero(src2) && insn->size == def->size && one_use(cond)) {
			unsigned s1 = log2_exact(def->src2->value);
			unsigned s2 = log2_exact(insn->src2->value);
			unsigned shift;

			if (s1 == s2)
				return replace_with_pseudo(insn, cond);

			// SEL(x & A, B, 0) --> SHIFT(x & A, S)
			insn->opcode = (s1 < s2) ? OP_SHL : OP_LSR;
			shift = (s1 < s2) ? (s2 - s1) : (s1 - s2);
			insn->src2 = value_pseudo(shift);
			return REPEAT_CSE;
		}
		break;
	}

	switch (DEF_OPCODE(def, src1)) {
	case OP_ADD: case OP_OR: case OP_XOR:
		if ((def->src1 == src2) && can_move_to(cond, def)) {
			// SEL(x, OP(y,z), y) --> OP(SEL(x, z, 0), y)
			swap_select(insn, def, cond, def->src2, value_pseudo(0), src2);
			return REPEAT_CSE;
		}
		if ((def->src2 == src2) && can_move_to(cond, def)) {
			// SEL(x, OP(z,y), y) --> OP(SEL(x, z, 0), y)
			swap_select(insn, def, cond, def->src1, value_pseudo(0), src2);
			return REPEAT_CSE;
		}
		break;
	}

	switch (DEF_OPCODE(def, src2)) {
	case OP_ADD: case OP_OR: case OP_XOR:
		if ((def->src1 == src1) && can_move_to(cond, def)) {
			// SEL(x, y, OP(y,z)) --> OP(SEL(x, 0, z), y)
			swap_select(insn, def, cond, value_pseudo(0), def->src2, src1);
			return REPEAT_CSE;
		}
		if ((def->src2 == src1) && can_move_to(cond, def)) {
			// SEL(x, y, OP(z,y)) --> OP(SEL(x, 0, z), y)
			swap_select(insn, def, cond, value_pseudo(0), def->src1, src1);
			return REPEAT_CSE;
		}
		break;
	}
	return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
movq %rdi, %rbx
movq 0x30(%rdi), %r14
movq 0x38(%rdi), %r15
movq 0x40(%rdi), %r12
movl 0x4(%r14), %ecx
cmpl $0x6, %ecx
jne 0x2763b
cmpq $0x0, 0x18(%r14)
cmoveq %r12, %r15
jmp 0x277fb
cmpq %r12, %r15
je 0x277fb
movl 0x4(%r15), %eax
cmpl $0x6, %eax
jne 0x276b0
cmpl $0x6, 0x4(%r12)
jne 0x27693
movq 0x18(%r15), %rdx
movq 0x18(%r12), %rsi
orq %rdx, %rsi
cmpq $0x1, %rsi
jne 0x27693
xorl %eax, %eax
testq %rdx, %rdx
setne %al
leal (%rax,%rax,8), %eax
cmoveq %r15, %r12
movl (%rbx), %ecx
andl $-0x80, %ecx
addl %ecx, %eax
addl $0x27, %eax
movl %eax, (%rbx)
movq 0x18(%rbx), %rax
movq %rax, 0x40(%rbx)
movq %r12, 0x38(%rbx)
jmp 0x27a2e
cmpl $0x6, %eax
setne %dl
cmpq %r12, %r14
setne %sil
orb %dl, %sil
jne 0x276b0
cmpq $0x0, 0x18(%r15)
je 0x277fb
cmpq %r15, %r14
jne 0x276c9
cmpl $0x6, 0x4(%r12)
jne 0x276c9
cmpq $0x0, 0x18(%r12)
je 0x27aaa
cmpl $0x3, %ecx
jne 0x278ea
movq 0x18(%r14), %r13
testq %r13, %r13
je 0x278ea
leaq 0x38(%rbx), %rsi
leaq 0x40(%rbx), %rcx
movl (%r13), %r8d
movl %r8d, %edx
andl $0x7f, %edx
leal -0x27(%rdx), %edi
cmpl $0x9, %edi
ja 0x2775b
leaq 0x1fa9c(%rip), %rax     # 0x4719c
movslq (%rax,%rdi,4), %rdx
addq %rax, %rdx
jmpq *%rdx
movq 0x8(%r14), %rdi
movq %rsi, %rbp
movq %r13, (%rsp)
movq %rcx, %r13
callq 0x2257f
movq (%rsp), %r8
testb %al, %al
jne 0x278ea
movl (%r8), %eax
movl %eax, %edi
andl $0x7f, %edi
leaq 0x1a4e9(%rip), %rdx     # 0x41c20
movl (%rdx,%rdi,8), %edx
andl $0x7f, %edx
andl $-0x80, %eax
orl %edx, %eax
movl %eax, (%r8)
movq %rbx, %rdi
movq %rbp, %rsi
movq %rbx, %rdx
movq %r13, %rcx
callq 0x2813a
jmp 0x27a2e
cmpl $0x16, %edx
je 0x27885
cmpl $0x41, %edx
jne 0x278ea
movq 0x38(%r13), %rdx
cmpl $0x6, 0x4(%rdx)
jne 0x278ea
movq 0x40(%r13), %rdi
cmpl $0x6, 0x4(%rdi)
jne 0x2788f
leaq 0x30(%rbx), %rbp
cmpq $0x0, 0x18(%rdi)
je 0x27a9f
cmpq $0x0, 0x18(%rdx)
jne 0x277fb
movq %rbx, %rdi
movq %rbx, %rdx
callq 0x2813a
jmp 0x27ab5
movq 0x30(%r13), %rax
cmpq %rax, %r15
jne 0x277be
cmpq 0x38(%r13), %r12
je 0x277d1
cmpq %rax, %r12
jne 0x278ea
cmpq 0x38(%r13), %r15
jne 0x278ea
movq %rbx, %rdi
movq %r12, %rsi
jmp 0x27801
movq 0x30(%r13), %rax
cmpq %rax, %r15
jne 0x277e8
cmpq 0x38(%r13), %r12
je 0x277fb
cmpq %rax, %r12
jne 0x278ea
cmpq 0x38(%r13), %r15
jne 0x278ea
movq %rbx, %rdi
movq %r15, %rsi
callq 0x3b384
movq %rbx, %rdi
xorl %esi, %esi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x24a3f
movq 0x8(%r14), %rdi
callq 0x2257f
testb %al, %al
jne 0x278ea
movq 0x38(%r13), %rax
cmpl $0x6, 0x4(%rax)
jne 0x278ea
cmpq $0x0, 0x18(%rax)
jne 0x278ea
cmpl $0x3, 0x4(%r12)
jne 0x278ea
movq 0x18(%r12), %rax
testq %rax, %rax
je 0x278ea
movl (%rax), %ecx
andl $0x7f, %ecx
cmpl $0x32, %ecx
jne 0x278ea
cmpq %r15, 0x30(%rax)
jne 0x278ea
movl (%r13), %eax
andl $-0x80, %eax
orl $0x2a, %eax
movl %eax, (%r13)
jmp 0x27a2e
movq 0x38(%r13), %rdx
cmpl $0x6, 0x4(%rdx)
jne 0x278ea
cmpl $0x6, %eax
setne %al
movq 0x18(%rdx), %rdx
leaq -0x1(%rdx), %rdi
xorq %rdi, %rdx
cmpq %rdi, %rdx
setbe %dl
orb %al, %dl
jne 0x278ea
movq 0x18(%r15), %rax
leaq -0x1(%rax), %rdx
xorq %rdx, %rax
cmpq %rdx, %rax
jbe 0x278ea
cmpl $0x6, 0x4(%r12)
jne 0x278ea
cmpq $0x0, 0x18(%r12)
jne 0x278ea
xorl (%rbx), %r8d
cmpl $0xff, %r8d
ja 0x278ea
movq 0x8(%r14), %rdi
movq %rsi, %rbp
callq 0x2257f
testb %al, %al
je 0x27ac9
cmpl $0x3, 0x4(%r15)
jne 0x27949
movq 0x18(%r15), %r13
testq %r13, %r13
je 0x27949
movl (%r13), %eax
andl $0x7f, %eax
cmpl $0x18, %eax
ja 0x27949
movl $0x1800100, %ecx        # imm = 0x1800100
btl %eax, %ecx
jae 0x27949
cmpq %r12, 0x30(%r13)
jne 0x2792b
movq 0x20(%r13), %rax
movq 0x8(%rax), %rdi
callq 0x2257f
testb %al, %al
je 0x279de
cmpq %r12, 0x38(%r13)
jne 0x27949
movq %r14, %rdi
movq %r13, %rsi
callq 0x28b81
testb %al, %al
je 0x27949
movq 0x30(%r13), %r15
jmp 0x27a10
xorl %ebp, %ebp
cmpl $0x3, 0x4(%r12)
jne 0x27a33
movq 0x18(%r12), %r12
testq %r12, %r12
je 0x27a33
movl (%r12), %eax
andl $0x7f, %eax
cmpl $0x18, %eax
ja 0x27a33
movl $0x1800100, %ecx        # imm = 0x1800100
btl %eax, %ecx
jae 0x27a33
cmpq %r15, 0x30(%r12)
jne 0x279a7
movq %r14, %rdi
movq %r12, %rsi
callq 0x28b81
testb %al, %al
je 0x279a7
xorl %edi, %edi
callq 0x13745
movq 0x38(%r12), %r8
jmp 0x279cd
cmpq %r15, 0x38(%r12)
jne 0x27a33
movq %r14, %rdi
movq %r12, %rsi
callq 0x28b81
testb %al, %al
je 0x27a33
xorl %edi, %edi
callq 0x13745
movq 0x30(%r12), %r8
movq %rbx, %rdi
movq %r12, %rsi
movq %r14, %rdx
movq %rax, %rcx
movq %r15, %r9
jmp 0x27a29
cmpl $0x3, 0x4(%r14)
jne 0x27a0c
movq 0x18(%r14), %rax
cmpq %r13, %rax
je 0x2792b
movq 0x8(%rax), %rdi
movq 0x8(%r13), %rsi
cmpq %rsi, %rdi
je 0x27a44
callq 0x3d05e
testb %al, %al
je 0x2792b
movq 0x38(%r13), %r15
xorl %edi, %edi
callq 0x13745
movq %rbx, %rdi
movq %r13, %rsi
movq %r14, %rdx
movq %r15, %rcx
movq %rax, %r8
movq %r12, %r9
callq 0x29df3
movl $0x1, %ebp
movl %ebp, %eax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x28(%rdi), %rcx
testq %rcx, %rcx
je 0x2792b
movq %rcx, %rdx
movzwl (%rdx), %edi
movsbl %dil, %esi
testw %si, %si
jle 0x27a91
movzwl %si, %esi
movzwl %di, %edi
xorl %r8d, %r8d
movq 0x18(%rdx,%r8,8), %r9
cmpl $0x100, %edi            # imm = 0x100
jb 0x27a7b
testq %r9, %r9
je 0x27a89
cmpq %rax, %r9
je 0x27a0c
cmpq %r13, %r9
je 0x2792b
incq %r8
cmpq %r8, %rsi
jne 0x27a69
movq 0x10(%rdx), %rdx
cmpq %rcx, %rdx
jne 0x27a54
jmp 0x2792b
xorq %rdx, %r15
xorq %rdi, %r12
orq %r15, %r12
jne 0x27ab5
movq %rbx, %rdi
movq %r14, %rsi
jmp 0x27801
movq 0x30(%r13), %rdx
movq %rbx, %rdi
movq %rbp, %rsi
callq 0x28562
jmp 0x27a2e
movq 0x38(%r13), %rax
bsrq 0x18(%rax), %rdi
xorq $0x3f, %rdi
movq (%rbp), %rax
bsrq 0x18(%rax), %rax
xorq $0x3f, %rax
cmpq %rax, %rdi
je 0x27aaa
xorl $0x3f, %eax
xorl $0x3f, %edi
movl %edi, %ecx
subl %eax, %ecx
negl %ecx
xorl %edx, %edx
subl %eax, %edi
setb %dl
cmovbl %ecx, %edi
movl (%rbx), %eax
andl $-0x80, %eax
leal (%rax,%rdx,2), %eax
addl $0xf, %eax
movl %eax, (%rbx)
callq 0x13745
movq %rax, 0x38(%rbx)
jmp 0x27a2e