// File: /workspace/github_c_makefile_star2_O3/lucvoo[P]sparse-dev/inline.c
// Function: copy_expression
static struct expression * copy_expression(struct expression *expr)
{
	if (!expr)
		return NULL;

	switch (expr->type) {
	/*
	 * EXPR_SYMBOL is the interesting case, we may need to replace the
	 * symbol to the new copy.
	 */
	case EXPR_SYMBOL: {
		struct symbol *sym = copy_symbol(expr->pos, expr->symbol);
		if (sym == expr->symbol)
			break;
		expr = dup_expression(expr);
		expr->symbol = sym;
		break;
	}

	/* Atomics, never change, just return the expression directly */
	case EXPR_VALUE:
	case EXPR_STRING:
	case EXPR_FVALUE:
	case EXPR_TYPE:
		break;

	/* Unops: check if the subexpression is unique */
	case EXPR_PREOP:
	case EXPR_POSTOP: {
		struct expression *unop = copy_expression(expr->unop);
		if (expr->unop == unop)
			break;
		expr = dup_expression(expr);
		expr->unop = unop;
		break;
	}

	case EXPR_SLICE: {
		struct expression *base = copy_expression(expr->base);
		expr = dup_expression(expr);
		expr->base = base;
		break;
	}

	/* Binops: copy left/right expressions */
	case EXPR_BINOP:
	case EXPR_COMMA:
	case EXPR_COMPARE:
	case EXPR_LOGICAL: {
		struct expression *left = copy_expression(expr->left);
		struct expression *right = copy_expression(expr->right);
		if (left == expr->left && right == expr->right)
			break;
		expr = dup_expression(expr);
		expr->left = left;
		expr->right = right;
		break;
	}

	case EXPR_ASSIGNMENT: {
		struct expression *left = copy_expression(expr->left);
		struct expression *right = copy_expression(expr->right);
		if (expr->op == '=' && left == expr->left && right == expr->right)
			break;
		expr = dup_expression(expr);
		expr->left = left;
		expr->right = right;
		break;
	}

	/* Dereference */
	case EXPR_DEREF: {
		struct expression *deref = copy_expression(expr->deref);
		expr = dup_expression(expr);
		expr->deref = deref;
		break;
	}

	/* Cast/sizeof/__alignof__ */
	case EXPR_CAST:
		if (!expr->cast_expression)
			return NULL;
		if (expr->cast_expression->type == EXPR_INITIALIZER) {
			struct expression *cast = expr->cast_expression;
			struct symbol *sym = expr->cast_type;
			expr = dup_expression(expr);
			expr->cast_expression = copy_expression(cast);
			expr->cast_type = alloc_symbol(sym->pos, sym->type);
			*expr->cast_type = *sym;
			break;
		}
	case EXPR_FORCE_CAST:
	case EXPR_IMPLIED_CAST:
	case EXPR_SIZEOF: 
	case EXPR_PTRSIZEOF:
	case EXPR_ALIGNOF: {
		struct expression *cast = copy_expression(expr->cast_expression);
		if (cast == expr->cast_expression)
			break;
		expr = dup_expression(expr);
		expr->cast_expression = cast;
		break;
	}

	/* Conditional expression */
	case EXPR_SELECT:
	case EXPR_CONDITIONAL: {
		struct expression *cond = copy_expression(expr->conditional);
		struct expression *valt = copy_expression(expr->cond_true);
		struct expression *valf = copy_expression(expr->cond_false);
		if (cond == expr->conditional && valt == expr->cond_true && valf == expr->cond_false)
			break;
		expr = dup_expression(expr);
		expr->conditional = cond;
		expr->cond_true = valt;
		expr->cond_false = valf;
		break;
	}

	/* Statement expression */
	case EXPR_STATEMENT: {
		struct statement *stmt = alloc_statement(expr->pos, STMT_COMPOUND);
		copy_statement(expr->statement, stmt);
		expr = dup_expression(expr);
		expr->statement = stmt;
		break;
	}

	/* Call expression */
	case EXPR_CALL: {
		struct expression *fn = copy_expression(expr->fn);
		struct expression_list *list = expr->args;
		struct expression *arg;

		expr = dup_expression(expr);
		expr->fn = fn;
		expr->args = NULL;
		FOR_EACH_PTR(list, arg) {
			add_expression(&expr->args, copy_expression(arg));
		} END_FOR_EACH_PTR(arg);
		break;
	}

	/* Initializer list statement */
	case EXPR_INITIALIZER: {
		struct expression_list *list = expr->expr_list;
		struct expression *entry;
		expr = dup_expression(expr);
		expr->expr_list = NULL;
		FOR_EACH_PTR(list, entry) {
			add_expression(&expr->expr_list, copy_expression(entry));
		} END_FOR_EACH_PTR(entry);
		break;
	}

	/* Label in inline function - hmm. */
	case EXPR_LABEL: {
		struct symbol *label_symbol = copy_symbol(expr->pos, expr->label_symbol);
		expr = dup_expression(expr);
		expr->label_symbol = label_symbol;
		break;
	}

	case EXPR_INDEX: {
		struct expression *sub_expr = copy_expression(expr->idx_expression);
		expr = dup_expression(expr);
		expr->idx_expression = sub_expr;
		break;
	}
		
	case EXPR_IDENTIFIER: {
		struct expression *sub_expr = copy_expression(expr->ident_expression);
		expr = dup_expression(expr);
		expr->ident_expression = sub_expr;
		break;
	}

	/* Position in initializer.. */
	case EXPR_POS: {
		struct expression *val = copy_expression(expr->init_expr);
		expr = dup_expression(expr);
		expr->init_expr = val;
		break;
	}
	case EXPR_OFFSETOF: {
		struct expression *val = copy_expression(expr->down);
		if (expr->op == '.') {
			if (expr->down != val) {
				expr = dup_expression(expr);
				expr->down = val;
			}
		} else {
			struct expression *idx = copy_expression(expr->index);
			if (expr->down != val || expr->index != idx) {
				expr = dup_expression(expr);
				expr->down = val;
				expr->index = idx;
			}
		}
		break;
	}
	case EXPR_GENERIC:
		expr = dup_expression(expr);
		expr->control = copy_expression(expr->control);
		if (!evaluate_expression(expr))
			return NULL;
		expr = copy_expression(expr);
		break;

	default:
		warning(expr->pos, "trying to copy expression type %d", expr->type);
	}
	return expr;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
movq %rdi, %rbx
leaq 0x2f275(%rip), %r14     # 0x403e8
testq %rbx, %rbx
je 0x113f2
movzbl (%rbx), %edx
leal -0x1(%rdx), %eax
cmpl $0x1e, %eax
ja 0x114a7
movslq (%r14,%rax,4), %rax
addq %r14, %rax
jmpq *%rax
movq %rbx, %rdi
callq 0x1174a
movq %rax, %rbx
movq 0x20(%rax), %rdi
callq 0x1115e
movq %rax, 0x20(%rbx)
movq %rbx, %rdi
callq 0x32223
testq %rax, %rax
jne 0x11173
jmp 0x113f2
movq 0x28(%rbx), %r14
movq %r14, %rdi
callq 0x1115e
cmpq 0x28(%rbx), %rax
je 0x115d8
movq %rax, %r14
movzbl (%rbx), %ebp
movq 0x8(%rbx), %r15
xorl %edi, %edi
callq 0x2f9f5
movq %r15, 0x8(%rax)
movw %bp, (%rax)
movaps (%rbx), %xmm0
movaps 0x10(%rbx), %xmm1
movaps 0x20(%rbx), %xmm2
movaps 0x30(%rbx), %xmm3
movaps %xmm2, 0x20(%rax)
movaps %xmm0, (%rax)
movaps %xmm1, 0x10(%rax)
movaps %xmm3, 0x30(%rax)
movq %r14, 0x28(%rax)
jmp 0x11371
movq 0x20(%rbx), %rdi
callq 0x1115e
movq %rax, %r14
movq 0x28(%rbx), %rdi
callq 0x1115e
movq %rax, %r15
cmpq 0x20(%rbx), %r14
jne 0x1123b
cmpq 0x28(%rbx), %r15
je 0x115d8
movzbl (%rbx), %ebp
movq 0x8(%rbx), %r12
xorl %edi, %edi
callq 0x2f9f5
movq %r12, 0x8(%rax)
movw %bp, (%rax)
movaps (%rbx), %xmm0
movaps 0x10(%rbx), %xmm1
movaps 0x20(%rbx), %xmm2
movaps 0x30(%rbx), %xmm3
movaps %xmm2, 0x20(%rax)
movaps %xmm0, (%rax)
movaps %xmm1, 0x10(%rax)
movaps %xmm3, 0x30(%rax)
movq %r14, 0x20(%rax)
movq %r15, 0x28(%rax)
jmp 0x11371
movq 0x20(%rbx), %rdi
callq 0x1115e
jmp 0x11529
movq 0x28(%rbx), %rdi
callq 0x1115e
movq %rax, %r14
movq %rbx, %rdi
callq 0x1174a
movq %rax, %rbx
movq %r14, 0x28(%rax)
jmp 0x115d8
movq 0x20(%rbx), %rdi
callq 0x1115e
cmpq %rax, 0x20(%rbx)
je 0x115d8
movq %rax, %r14
movzbl (%rbx), %ebp
movq 0x8(%rbx), %r15
xorl %edi, %edi
callq 0x2f9f5
movq %r15, 0x8(%rax)
movw %bp, (%rax)
movaps (%rbx), %xmm0
movaps 0x10(%rbx), %xmm1
movaps 0x20(%rbx), %xmm2
movaps 0x30(%rbx), %xmm3
movaps %xmm2, 0x20(%rax)
movaps %xmm0, (%rax)
movaps %xmm1, 0x10(%rax)
movaps %xmm3, 0x30(%rax)
movq %r14, 0x20(%rax)
jmp 0x11371
movq 0x20(%rbx), %rdi
callq 0x1115e
movq %rax, %r14
movq 0x28(%rbx), %rdi
callq 0x1115e
movq %rax, %r15
movq 0x30(%rbx), %rdi
callq 0x1115e
movq %rax, %r12
cmpq 0x20(%rbx), %r14
jne 0x11332
cmpq 0x28(%rbx), %r15
jne 0x11332
cmpq 0x30(%rbx), %r12
je 0x115d8
movzbl (%rbx), %ebp
movq 0x8(%rbx), %r13
xorl %edi, %edi
callq 0x2f9f5
movq %r13, 0x8(%rax)
movw %bp, (%rax)
movaps (%rbx), %xmm0
movaps 0x10(%rbx), %xmm1
movaps 0x20(%rbx), %xmm2
movaps 0x30(%rbx), %xmm3
movaps %xmm2, 0x20(%rax)
movaps %xmm3, 0x30(%rax)
movaps %xmm0, (%rax)
movaps %xmm1, 0x10(%rax)
movq %r14, 0x20(%rax)
movq %r15, 0x28(%rax)
movq %r12, 0x30(%rax)
movq %rax, %rbx
jmp 0x115d8
movq 0x28(%rbx), %rdi
callq 0x1115e
movq %rax, %r14
cmpl $0x2e, 0x4(%rbx)
jne 0x115ea
cmpq %r14, 0x28(%rbx)
jne 0x11295
jmp 0x115d8
movq 0x28(%rbx), %r14
testq %r14, %r14
je 0x113f2
cmpb $0x18, (%r14)
jne 0x111c2
movq 0x20(%rbx), %r15
movq %rbx, %rdi
callq 0x1174a
movq %rax, %rbx
movq %r14, %rdi
callq 0x1115e
movq %rax, 0x28(%rbx)
movzbl (%r15), %esi
movq 0x4(%r15), %rdi
callq 0x2b00b
movq %rax, 0x20(%rbx)
movl $0xe0, %edx
movq %rax, %rdi
movq %r15, %rsi
callq 0xe1e0
jmp 0x115d8
xorl %ebx, %ebx
jmp 0x115d8
movq 0x20(%rbx), %rdi
callq 0x1115e
movq %rax, %r14
movq 0x28(%rbx), %r15
movq %rbx, %rdi
callq 0x1174a
movq %rax, %rbx
movq %r14, 0x20(%rax)
movq $0x0, 0x28(%rax)
testq %r15, %r15
je 0x115d8
movq %rbx, %r14
addq $0x28, %r14
movq %r15, %r12
movzwl (%r12), %eax
testb %al, %al
jle 0x11478
xorl %r13d, %r13d
movq 0x18(%r12,%r13,8), %rdi
movzwl %ax, %ecx
cmpl $0x100, %ecx            # imm = 0x100
jb 0x11454
testq %rdi, %rdi
je 0x11469
callq 0x1115e
movq %r14, %rdi
movq %rax, %rsi
callq 0x227b4
movzwl (%r12), %eax
incq %r13
movzwl %ax, %ecx
movsbq %cl, %rcx
cmpq %rcx, %r13
jl 0x1143f
movq 0x10(%r12), %r12
cmpq %r15, %r12
jne 0x11433
jmp 0x115d8
movq 0x38(%rbx), %rdi
callq 0x1115e
movq %rax, %r14
movq %rbx, %rdi
callq 0x1174a
movq %rax, %rbx
movq %r14, 0x38(%rax)
jmp 0x115d8
movq 0x8(%rbx), %rdi
leaq 0x2effb(%rip), %rsi     # 0x404ad
xorl %eax, %eax
callq 0x118fc
jmp 0x115d8
movq 0x8(%rbx), %rdi
movq 0x20(%rbx), %rsi
callq 0x11111
cmpq 0x20(%rbx), %rax
jne 0x11529
jmp 0x115d8
movq 0x20(%rbx), %rdi
callq 0x1115e
movq %rax, %r14
movq 0x28(%rbx), %rdi
callq 0x1115e
movq %rax, %r15
cmpl $0x3d, 0x4(%rbx)
jne 0x11504
cmpq 0x20(%rbx), %r14
jne 0x11504
cmpq 0x28(%rbx), %r15
je 0x115d8
movq %rbx, %rdi
callq 0x1174a
movq %rax, %rbx
movq %r14, 0x20(%rax)
movq %r15, 0x28(%rax)
jmp 0x115d8
movq 0x8(%rbx), %rdi
movq 0x20(%rbx), %rsi
callq 0x11111
movq %rax, %r14
jmp 0x115c9
movq 0x20(%rbx), %r15
movq %rbx, %rdi
callq 0x1174a
movq %rax, %rbx
movq $0x0, 0x20(%rax)
testq %r15, %r15
je 0x115d8
movq %rbx, %r14
addq $0x20, %r14
movq %r15, %r12
movzwl (%r12), %eax
testb %al, %al
jle 0x115a0
xorl %r13d, %r13d
movq 0x18(%r12,%r13,8), %rdi
movzwl %ax, %ecx
cmpl $0x100, %ecx            # imm = 0x100
jb 0x1157c
testq %rdi, %rdi
je 0x11591
callq 0x1115e
movq %r14, %rdi
movq %rax, %rsi
callq 0x227b4
movzwl (%r12), %eax
incq %r13
movzwl %ax, %ecx
movsbq %cl, %rcx
cmpq %rcx, %r13
jl 0x11567
movq 0x10(%r12), %r12
cmpq %r15, %r12
jne 0x1155b
jmp 0x115d8
movq 0x8(%rbx), %rdi
movl $0x3, %esi
callq 0x195bf
movq %rax, %r14
movq 0x20(%rbx), %rdi
movq %rax, %rsi
callq 0x10ad3
movq %rbx, %rdi
callq 0x1174a
movq %rax, %rbx
movq %r14, 0x20(%rax)
movq %rbx, %rax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x30(%rbx), %rdi
callq 0x1115e
movq %rax, %r15
cmpq %r14, 0x28(%rbx)
jne 0x11602
cmpq %r15, 0x30(%rbx)
je 0x115d8
movq %rbx, %rdi
callq 0x1174a
movq %rax, %rbx
movq %r14, 0x28(%rax)
movq %r15, 0x30(%rax)
jmp 0x115d8