// File: /workspace/github_c_makefile_star2_O2/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 %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
movq %rdi, %rbx
leaq 0x28ae1(%rip), %r14     # 0x393e8
testq %rbx, %rbx
je 0x10aaf
movzbl (%rbx), %edx
leal -0x1(%rdx), %eax
cmpl $0x1e, %eax
ja 0x10b4e
movslq (%r14,%rax,4), %rax
addq %r14, %rax
jmpq *%rax
movq %rbx, %rdi
callq 0x10d9c
movq %rax, %rbx
movq 0x20(%rax), %rdi
callq 0x108f4
movq %rax, 0x20(%rbx)
movq %rbx, %rdi
callq 0x2d0ed
testq %rax, %rax
jne 0x10907
jmp 0x10aaf
movq 0x28(%rbx), %r14
movq %r14, %rdi
callq 0x108f4
cmpq 0x28(%rbx), %rax
jne 0x109b1
jmp 0x10bcd
movq 0x20(%rbx), %rdi
callq 0x108f4
movq %rax, %r14
movq 0x28(%rbx), %rdi
callq 0x108f4
movq %rax, %r15
cmpq 0x20(%rbx), %r14
jne 0x10b99
cmpq 0x28(%rbx), %r15
jne 0x10b99
jmp 0x10bcd
movq 0x20(%rbx), %rdi
callq 0x108f4
jmp 0x10bbb
movq 0x28(%rbx), %rdi
callq 0x108f4
movq %rax, %r14
movq %rbx, %rdi
callq 0x10d9c
movq %rax, %rbx
movq %r14, 0x28(%rax)
jmp 0x10bcd
movq 0x20(%rbx), %rdi
callq 0x108f4
cmpq %rax, 0x20(%rbx)
jne 0x10bbb
jmp 0x10bcd
movq 0x20(%rbx), %rdi
callq 0x108f4
movq %rax, %r14
movq 0x28(%rbx), %rdi
callq 0x108f4
movq %rax, %r15
movq 0x30(%rbx), %rdi
callq 0x108f4
movq %rax, %r12
cmpq 0x20(%rbx), %r14
jne 0x10a1a
cmpq 0x28(%rbx), %r15
jne 0x10a1a
cmpq 0x30(%rbx), %r12
je 0x10bcd
movq %rbx, %rdi
callq 0x10d9c
movq %rax, %rbx
movq %r14, 0x20(%rax)
movq %r15, 0x28(%rax)
movq %r12, 0x30(%rax)
jmp 0x10bcd
movq 0x28(%rbx), %rdi
callq 0x108f4
movq %rax, %r14
cmpl $0x2e, 0x4(%rbx)
jne 0x10c5e
cmpq %r14, 0x28(%rbx)
jne 0x109b4
jmp 0x10bcd
movq 0x28(%rbx), %r14
testq %r14, %r14
je 0x10aaf
cmpb $0x18, (%r14)
jne 0x10956
movq 0x20(%rbx), %r15
movq %rbx, %rdi
callq 0x10d9c
movq %rax, %rbx
movq %r14, %rdi
callq 0x108f4
movq %rax, 0x28(%rbx)
movzbl (%r15), %esi
movq 0x4(%r15), %rdi
callq 0x2671f
movq %rax, 0x20(%rbx)
movl $0xe0, %edx
movq %rax, %rdi
movq %r15, %rsi
callq 0xe1e0
jmp 0x10bcd
xorl %ebx, %ebx
jmp 0x10bcd
movq 0x20(%rbx), %rdi
callq 0x108f4
movq %rax, %r14
movq 0x28(%rbx), %r15
movq %rbx, %rdi
callq 0x10d9c
movq %rax, %rbx
movq %r14, 0x20(%rax)
andq $0x0, 0x28(%rax)
testq %r15, %r15
je 0x10bcd
movq %rbx, %r14
addq $0x28, %r14
movq %r15, %r12
xorl %r13d, %r13d
movl (%r12), %eax
movsbq %al, %rcx
cmpq %rcx, %r13
jge 0x10b22
movq 0x18(%r12,%r13,8), %rdi
cmpw $0x100, %ax             # imm = 0x100
jb 0x10b0d
testq %rdi, %rdi
je 0x10b1d
callq 0x108f4
movq %r14, %rdi
movq %rax, %rsi
callq 0x1fae9
incq %r13
jmp 0x10af0
movq 0x10(%r12), %r12
cmpq %r15, %r12
jne 0x10aed
jmp 0x10bcd
movq 0x38(%rbx), %rdi
callq 0x108f4
movq %rax, %r14
movq %rbx, %rdi
callq 0x10d9c
movq %rax, %rbx
movq %r14, 0x38(%rax)
jmp 0x10bcd
movq 0x8(%rbx), %rdi
leaq 0x28954(%rip), %rsi     # 0x394ad
xorl %eax, %eax
callq 0x1108a
jmp 0x10bcd
movq 0x8(%rbx), %rdi
movq 0x20(%rbx), %rsi
callq 0x1088a
cmpq 0x20(%rbx), %rax
jne 0x10bbb
jmp 0x10bcd
movq 0x20(%rbx), %rdi
callq 0x108f4
movq %rax, %r14
movq 0x28(%rbx), %rdi
callq 0x108f4
movq %rax, %r15
cmpl $0x3d, 0x4(%rbx)
je 0x10981
movq %rbx, %rdi
callq 0x10d9c
movq %rax, %rbx
movq %r14, 0x20(%rax)
movq %r15, 0x28(%rax)
jmp 0x10bcd
movq 0x8(%rbx), %rdi
movq 0x20(%rbx), %rsi
callq 0x1088a
movq %rax, %r14
movq %rbx, %rdi
callq 0x10d9c
movq %rax, %rbx
movq %r14, 0x20(%rax)
movq %rbx, %rax
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
retq
movq 0x20(%rbx), %r15
movq %rbx, %rdi
callq 0x10d9c
movq %rax, %rbx
andq $0x0, 0x20(%rax)
testq %r15, %r15
je 0x10bcd
movq %rbx, %r14
addq $0x20, %r14
movq %r15, %r12
xorl %r13d, %r13d
movl (%r12), %eax
movsbq %al, %rcx
cmpq %rcx, %r13
jge 0x10c32
movq 0x18(%r12,%r13,8), %rdi
cmpw $0x100, %ax             # imm = 0x100
jb 0x10c1d
testq %rdi, %rdi
je 0x10c2d
callq 0x108f4
movq %r14, %rdi
movq %rax, %rsi
callq 0x1fae9
incq %r13
jmp 0x10c00
movq 0x10(%r12), %r12
cmpq %r15, %r12
jne 0x10bfd
jmp 0x10bcd
movq 0x8(%rbx), %rdi
pushq $0x3
popq %rsi
callq 0x17530
movq %rax, %r14
movq 0x20(%rbx), %rdi
movq %rax, %rsi
callq 0x1034c
jmp 0x10bbe
movq 0x30(%rbx), %rdi
callq 0x108f4
movq %rax, %r15
cmpq %r14, 0x28(%rbx)
jne 0x10c7a
cmpq %r15, 0x30(%rbx)
je 0x10bcd
movq %rbx, %rdi
callq 0x10d9c
movq %rax, %rbx
movq %r14, 0x28(%rax)
movq %r15, 0x30(%rax)
jmp 0x10bcd