// File: /workspace/github_c_makefile_star2_O3/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 0x607c
movq 0x18(%rbx), %rdi
callq 0x603c
movq %rax, %r14
movl 0x14(%rbx), %eax
cmpl $0x4a, %eax
jne 0x60b8
movl (%r14), %eax
cmpl $0x7, %eax
jne 0x6100
cmpl $0x4b, 0x14(%r14)
jne 0x6410
movq 0x18(%r14), %rbx
jmp 0x6044
cmpl $0x9, %eax
ja 0x6410
movl %eax, %eax
leaq 0xcfaa(%rip), %rcx      # 0x13038
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x30(%rbx), %rax
cmpl $0x3, 0x8(%rax)
jne 0x6410
movl $0x1, (%rbx)
movq 0x40(%rax), %rax
movq %rax, 0x30(%rbx)
jmp 0x6410
cmpl $0x4b, %eax
je 0x6410
cmpl $0x1, (%r14)
jne 0x6410
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 0x62b3
cmpl $0x4d, %ecx
jne 0x62cb
xorl %eax, %eax
subq 0x30(%r14), %rax
jmp 0x61a1
cmpl $0x2, %eax
jne 0x6410
movq %r14, %rdi
callq 0x55fe
movq %rax, 0x30(%r14)
movl $0x0, (%r14)
movq %r14, 0x18(%rbx)
jmp 0x6410
movq 0x30(%rbx), %r14
cmpl $0x0, 0x44(%r14)
jne 0x6410
movq %r14, %rdi
callq 0xe324
movq %rax, 0x20(%r14)
movq 0x38(%rbx), %rsi
movq %r14, %rdi
callq 0x10ff3
movl $0x0, (%rbx)
movq %r14, 0x30(%rbx)
jmp 0x6410
movq 0x8(%rbx), %r15
movq 0x18(%rbx), %rdi
callq 0x603c
movq %rax, %r14
cmpl $0x1, (%rax)
jne 0x61e5
movl $0x1, (%rbx)
movq 0x8(%r14), %rax
movl 0x4(%rax), %ecx
testb $0x2, %cl
je 0x618d
testb $0x20, 0x4(%r15)
jne 0x62de
testb $0x20, %cl
je 0x619d
testb $0x2, 0x4(%r15)
jne 0x62fb
movq 0x30(%r14), %rax
movq %rax, 0x30(%rbx)
jmp 0x6408
movq 0x30(%rbx), %rdi
callq 0x603c
movq %rax, %r14
movq 0x38(%rbx), %rdi
callq 0x603c
movq %r14, 0x30(%rbx)
movq %rax, 0x38(%rbx)
movl 0x14(%rbx), %esi
cmpl $0x5b, %esi
jg 0x6219
cmpl $0x4c, %esi
je 0x625c
cmpl $0x4d, %esi
jne 0x623e
movq %rax, %rcx
jmp 0x626a
movq 0x8(%r14), %rax
cmpl $0xc, (%rax)
jne 0x6410
cmpl $0xc, (%r15)
je 0x6236
testb $0x2, 0x4(%r15)
je 0x6410
movq 0x10(%r15), %rax
leaq 0x15aa2(%rip), %rcx     # 0x1bcb0
cmpq 0x10(%rcx), %rax
je 0x6236
jmp 0x6410
cmpl $0x5c, %esi
je 0x6298
cmpl $0x5d, %esi
jne 0x623e
cmpl $0x1, (%r14)
jne 0x6410
cmpq $0x0, 0x30(%r14)
cmoveq %rax, %r14
movq %r14, %rbx
jmp 0x6410
cmpl $0x1, (%r14)
jne 0x6410
cmpl $0x1, (%rax)
jne 0x6410
movq %rbx, %rdi
movq %r14, %rdx
movq %rax, %rcx
jmp 0x628e
cmpl $0x9, (%rax)
movq %rax, %rcx
cmoveq %r14, %rcx
cmoveq %rax, %r14
cmpl $0x1, (%rcx)
jne 0x6410
movl (%r14), %edx
cmpl $0x9, %edx
je 0x634d
cmpl $0x1, %edx
jne 0x6410
movq %rbx, %rdi
movq %r14, %rdx
callq 0x6474
jmp 0x6410
cmpl $0x1, (%r14)
jne 0x6410
cmpq $0x0, 0x30(%r14)
cmoveq %r14, %rax
movq %rax, %rbx
jmp 0x6410
movsd 0x30(%r14), %xmm0
xorpd 0xcd4f(%rip), %xmm0     # 0x13010
movlpd %xmm0, 0x30(%rbx)
jmp 0x6408
leaq 0xcf02(%rip), %rdi      # 0x131d4
xorl %eax, %eax
callq 0xe058
jmp 0x6408
movq 0x30(%r14), %rcx
cmpb $0x1, 0x40(%rax)
jne 0x638a
cvtsi2sd %rcx, %xmm0
movsd %xmm0, 0x30(%rbx)
jmp 0x6408
movsd 0x30(%r14), %xmm0
cmpb $0x1, 0x40(%r15)
jne 0x63b2
movsd 0xcd1c(%rip), %xmm1     # 0x13030
ucomisd %xmm0, %xmm1
ja 0x6324
ucomisd 0xcd06(%rip), %xmm0     # 0x13028
jb 0x6343
leaq 0x15ddd(%rip), %rdi     # 0x1c108
addq $0x8, %rdi
leaq 0xcdf6(%rip), %rsi      # 0x1312c
movb $0x1, %al
callq 0xd55c
movsd 0x30(%r14), %xmm0
cvttsd2si %xmm0, %rax
jmp 0x61a1
movq 0x8(%r14), %rdx
cmpl $0xc, (%rdx)
jne 0x6410
cmpl $0x4c, 0x14(%r14)
jne 0x6410
movq 0x38(%r14), %rdx
cmpl $0x1, (%rdx)
jne 0x6410
movq %rax, %rdi
callq 0x6474
movl $0x4c, 0x14(%rbx)
movq 0x30(%r14), %rax
jmp 0x60af
movq %rcx, %xmm0
punpckldq 0xcc59(%rip), %xmm0 # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0xcc61(%rip), %xmm0     # 0x13000
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
movsd %xmm1, 0x30(%rbx)
jmp 0x6408
xorpd %xmm1, %xmm1
ucomisd %xmm0, %xmm1
ja 0x63c6
ucomisd 0xcc5c(%rip), %xmm0     # 0x13020
jb 0x63e5
leaq 0x15d3b(%rip), %rdi     # 0x1c108
addq $0x8, %rdi
leaq 0xcda7(%rip), %rsi      # 0x1317f
movb $0x1, %al
callq 0xd55c
movsd 0x30(%r14), %xmm0
cvttsd2si %xmm0, %rax
movq %rax, %rcx
subsd 0xcc33(%rip), %xmm0     # 0x13028
cvttsd2si %xmm0, %rdx
sarq $0x3f, %rcx
andq %rcx, %rdx
orq %rax, %rdx
movq %rdx, 0x30(%rbx)
movq %rbx, %rdi
callq 0x6419
movq %rbx, %rax
popq %rbx
popq %r14
popq %r15
retq