// File: /workspace/github_c_makefile_star2_O1/michaelforney[P]cproc/eval.c
// Function: eval
struct expr *
eval(struct expr *expr)
{
	struct expr *l, *r, *c;
	struct decl *d;
	struct type *t;

	t = expr->type;
	switch (expr->kind) {
	case EXPRIDENT:
		d = expr->u.ident.decl;
		if (d->kind != DECLCONST)
			break;
		expr->kind = EXPRCONST;
		expr->u.constant.u = d->u.enumconst;
		break;
	case EXPRCOMPOUND:
		d = expr->u.compound.decl;
		if (d->u.obj.storage != SDSTATIC)
			break;
		d->value = mkglobal(d);
		emitdata(d, expr->u.compound.init);
		expr->kind = EXPRIDENT;
		expr->u.ident.decl = d;
		break;
	case EXPRUNARY:
		l = eval(expr->base);
		switch (expr->op) {
		case TBAND:
			switch (l->kind) {
			case EXPRUNARY:
				if (l->op == TMUL)
					expr = eval(l->base);
				break;
			case EXPRSTRING:
				l->u.ident.decl = stringdecl(l);
				l->kind = EXPRIDENT;
				expr->base = l;
				break;
			}
			break;
		case TMUL:
			break;
		default:
			if (l->kind != EXPRCONST)
				break;
			unary(expr, expr->op, l);
			break;
		}
		break;
	case EXPRCAST:
		l = eval(expr->base);
		if (l->kind == EXPRCONST) {
			expr->kind = EXPRCONST;
			if (l->type->prop & PROPINT && t->prop & PROPFLOAT) {
				if (l->type->u.basic.issigned)
					expr->u.constant.f = l->u.constant.i;
				else
					expr->u.constant.f = l->u.constant.u;
			} else if (l->type->prop & PROPFLOAT && t->prop & PROPINT) {
				if (t->u.basic.issigned) {
					if (l->u.constant.f < -0x1p63 || l->u.constant.f >= 0x1p63)
						error(&tok.loc, "integer part of floating-point constant %g cannot be represented as signed integer", l->u.constant.f);
					expr->u.constant.i = l->u.constant.f;
				} else {
					if (l->u.constant.f < 0.0 || l->u.constant.f >= 0x1p64)
						error(&tok.loc, "integer part of floating-point constant %g cannot be represented as unsigned integer", l->u.constant.f);
					expr->u.constant.u = l->u.constant.f;
				}
			} else {
				expr->u.constant = l->u.constant;
			}
			cast(expr);
		} else if (l->type->kind == TYPEPOINTER) {
			/*
			A cast from a pointer to integer is not a valid constant
			expression, but C11 allows implementations to recognize
			other forms of constant expressions (6.6p10), and some
			programs expect this functionality.
			*/
			if (t->kind == TYPEPOINTER || t->prop & PROPINT && t->size == typelong.size)
				expr = l;
		}
		break;
	case EXPRBINARY:
		l = eval(expr->u.binary.l);
		r = eval(expr->u.binary.r);
		expr->u.binary.l = l;
		expr->u.binary.r = r;
		switch (expr->op) {
		case TADD:
			if (r->kind == EXPRBINARY)
				c = l, l = r, r = c;
			/* fallthrough */
		case TSUB:
			if (r->kind != EXPRCONST)
				break;
			if (l->kind == EXPRCONST) {
				binary(expr, expr->op, l, r);
			} else if (l->kind == EXPRBINARY && l->type->kind == TYPEPOINTER && l->op == TADD && l->u.binary.r->kind == EXPRCONST) {
				/* (P + C1) ± C2  ->  P + (C1 ± C2) */
				binary(expr->u.binary.r, expr->op, l->u.binary.r, r);
				expr->op = TADD;
				expr->u.binary.l = l->u.binary.l;
			}
			break;
		case TLOR:
			if (l->kind != EXPRCONST)
				break;
			return l->u.constant.u ? l : r;
		case TLAND:
			if (l->kind != EXPRCONST)
				break;
			return l->u.constant.u ? r : l;
		default:
			if (l->kind != EXPRCONST || r->kind != EXPRCONST)
				break;
			binary(expr, expr->op, l, r);
		}
		break;
	}

	return expr;
}

// Assembly:
pushq %r15
pushq %r14
pushq %rbx
movq %rdi, %rbx
movl (%rbx), %eax
cmpl $0x7, %eax
jne 0x620c
movq 0x18(%rbx), %rdi
callq 0x61cc
movq %rax, %r14
movl 0x14(%rbx), %eax
cmpl $0x4a, %eax
jne 0x6248
movl (%r14), %eax
cmpl $0x7, %eax
jne 0x6290
cmpl $0x4b, 0x14(%r14)
jne 0x659b
movq 0x18(%r14), %rbx
jmp 0x61d4
cmpl $0x9, %eax
ja 0x659b
movl %eax, %eax
leaq 0xcdba(%rip), %rcx      # 0x12fd8
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x30(%rbx), %rax
cmpl $0x3, 0x8(%rax)
jne 0x659b
movl $0x1, (%rbx)
movq 0x40(%rax), %rax
movq %rax, 0x30(%rbx)
jmp 0x659b
cmpl $0x4b, %eax
je 0x659b
cmpl $0x1, (%r14)
jne 0x659b
movl $0x1, (%rbx)
movq 0x8(%r14), %rcx
movl 0x4(%rcx), %ecx
andl $0x20, %ecx
shll $0x3, %ecx
orl %eax, %ecx
cmpl $0x14d, %ecx            # imm = 0x14D
je 0x6443
cmpl $0x4d, %ecx
jne 0x645b
xorl %eax, %eax
subq 0x30(%r14), %rax
jmp 0x6331
cmpl $0x2, %eax
jne 0x659b
movq %r14, %rdi
callq 0x5783
movq %rax, 0x30(%r14)
movl $0x0, (%r14)
movq %r14, 0x18(%rbx)
jmp 0x659b
movq 0x30(%rbx), %r14
cmpl $0x0, 0x44(%r14)
jne 0x659b
movq %r14, %rdi
callq 0xe328
movq %rax, 0x20(%r14)
movq 0x38(%rbx), %rsi
movq %r14, %rdi
callq 0x10fd7
movl $0x0, (%rbx)
movq %r14, 0x30(%rbx)
jmp 0x659b
movq 0x8(%rbx), %r15
movq 0x18(%rbx), %rdi
callq 0x61cc
movq %rax, %r14
cmpl $0x1, (%rax)
jne 0x6375
movl $0x1, (%rbx)
movq 0x8(%r14), %rax
movl 0x4(%rax), %ecx
testb $0x2, %cl
je 0x631d
testb $0x20, 0x4(%r15)
jne 0x646e
testb $0x20, %cl
je 0x632d
testb $0x2, 0x4(%r15)
jne 0x648b
movq 0x30(%r14), %rax
movq %rax, 0x30(%rbx)
jmp 0x6593
movq 0x30(%rbx), %rdi
callq 0x61cc
movq %rax, %r14
movq 0x38(%rbx), %rdi
callq 0x61cc
movq %r14, 0x30(%rbx)
movq %rax, 0x38(%rbx)
movl 0x14(%rbx), %esi
cmpl $0x5b, %esi
jg 0x63a9
cmpl $0x4c, %esi
je 0x63ec
cmpl $0x4d, %esi
jne 0x63ce
movq %rax, %rcx
jmp 0x63fa
movq 0x8(%r14), %rax
cmpl $0xc, (%rax)
jne 0x659b
cmpl $0xc, (%r15)
je 0x63c6
testb $0x2, 0x4(%r15)
je 0x659b
movq 0x10(%r15), %rax
leaq 0x15912(%rip), %rcx     # 0x1bcb0
cmpq 0x10(%rcx), %rax
je 0x63c6
jmp 0x659b
cmpl $0x5c, %esi
je 0x6428
cmpl $0x5d, %esi
jne 0x63ce
cmpl $0x1, (%r14)
jne 0x659b
cmpq $0x0, 0x30(%r14)
cmoveq %rax, %r14
movq %r14, %rbx
jmp 0x659b
cmpl $0x1, (%r14)
jne 0x659b
cmpl $0x1, (%rax)
jne 0x659b
movq %rbx, %rdi
movq %r14, %rdx
movq %rax, %rcx
jmp 0x641e
cmpl $0x9, (%rax)
movq %rax, %rcx
cmoveq %r14, %rcx
cmoveq %rax, %r14
cmpl $0x1, (%rcx)
jne 0x659b
movl (%r14), %edx
cmpl $0x9, %edx
je 0x64d8
cmpl $0x1, %edx
jne 0x659b
movq %rbx, %rdi
movq %r14, %rdx
callq 0x65ff
jmp 0x659b
cmpl $0x1, (%r14)
jne 0x659b
cmpq $0x0, 0x30(%r14)
cmoveq %r14, %rax
movq %rax, %rbx
jmp 0x659b
movsd 0x30(%r14), %xmm0
xorpd 0xcb5f(%rip), %xmm0     # 0x12fb0
movlpd %xmm0, 0x30(%rbx)
jmp 0x6593
leaq 0xcd12(%rip), %rdi      # 0x13174
xorl %eax, %eax
callq 0xe054
jmp 0x6593
movq 0x30(%r14), %rcx
cmpb $0x1, 0x40(%rax)
jne 0x6515
cvtsi2sd %rcx, %xmm0
movsd %xmm0, 0x30(%rbx)
jmp 0x6593
movsd 0x30(%r14), %xmm0
cmpb $0x1, 0x40(%r15)
jne 0x653d
movsd 0xcb2c(%rip), %xmm1     # 0x12fd0
ucomisd %xmm0, %xmm1
ja 0x64b4
ucomisd 0xcb16(%rip), %xmm0     # 0x12fc8
jb 0x64cd
leaq 0x15c4d(%rip), %rdi     # 0x1c108
addq $0x8, %rdi
leaq 0xcc06(%rip), %rsi      # 0x130cc
movb $0x1, %al
callq 0xd56a
cvttsd2si 0x30(%r14), %rax
jmp 0x6331
movq 0x8(%r14), %rdx
cmpl $0xc, (%rdx)
jne 0x659b
cmpl $0x4c, 0x14(%r14)
jne 0x659b
movq 0x38(%r14), %rdx
cmpl $0x1, (%rdx)
jne 0x659b
movq %rax, %rdi
callq 0x65ff
movl $0x4c, 0x14(%rbx)
movq 0x30(%r14), %rax
jmp 0x623f
movq %rcx, %xmm0
punpckldq 0xca6e(%rip), %xmm0 # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0xca76(%rip), %xmm0     # 0x12fa0
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
movsd %xmm1, 0x30(%rbx)
jmp 0x6593
xorpd %xmm1, %xmm1
ucomisd %xmm0, %xmm1
ja 0x6551
ucomisd 0xca71(%rip), %xmm0     # 0x12fc0
jb 0x656a
leaq 0x15bb0(%rip), %rdi     # 0x1c108
addq $0x8, %rdi
leaq 0xcbbc(%rip), %rsi      # 0x1311f
movb $0x1, %al
callq 0xd56a
movsd 0x30(%r14), %xmm0
cvttsd2si %xmm0, %rax
movq %rax, %rcx
subsd 0xca48(%rip), %xmm0     # 0x12fc8
cvttsd2si %xmm0, %rdx
sarq $0x3f, %rcx
andq %rcx, %rdx
orq %rax, %rdx
movq %rdx, 0x30(%rbx)
movq %rbx, %rdi
callq 0x65a4
movq %rbx, %rax
popq %rbx
popq %r14
popq %r15
retq