xref: /illumos-gate/usr/src/tools/smatch/src/inline.c (revision c85f09cc)
11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Sparse - a semantic source parser.
31f5207b7SJohn Levon  *
41f5207b7SJohn Levon  * Copyright (C) 2003 Transmeta Corp.
51f5207b7SJohn Levon  *               2003-2004 Linus Torvalds
61f5207b7SJohn Levon  *
71f5207b7SJohn Levon  * Permission is hereby granted, free of charge, to any person obtaining a copy
81f5207b7SJohn Levon  * of this software and associated documentation files (the "Software"), to deal
91f5207b7SJohn Levon  * in the Software without restriction, including without limitation the rights
101f5207b7SJohn Levon  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
111f5207b7SJohn Levon  * copies of the Software, and to permit persons to whom the Software is
121f5207b7SJohn Levon  * furnished to do so, subject to the following conditions:
131f5207b7SJohn Levon  *
141f5207b7SJohn Levon  * The above copyright notice and this permission notice shall be included in
151f5207b7SJohn Levon  * all copies or substantial portions of the Software.
161f5207b7SJohn Levon  *
171f5207b7SJohn Levon  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
181f5207b7SJohn Levon  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
191f5207b7SJohn Levon  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
201f5207b7SJohn Levon  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
211f5207b7SJohn Levon  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
221f5207b7SJohn Levon  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
231f5207b7SJohn Levon  * THE SOFTWARE.
241f5207b7SJohn Levon  */
251f5207b7SJohn Levon 
261f5207b7SJohn Levon #include <stdlib.h>
271f5207b7SJohn Levon #include <stdio.h>
281f5207b7SJohn Levon 
291f5207b7SJohn Levon #include "lib.h"
301f5207b7SJohn Levon #include "allocate.h"
311f5207b7SJohn Levon #include "token.h"
321f5207b7SJohn Levon #include "parse.h"
331f5207b7SJohn Levon #include "symbol.h"
341f5207b7SJohn Levon #include "expression.h"
35*c85f09ccSJohn Levon #include "evaluate.h"
36*c85f09ccSJohn Levon 
37*c85f09ccSJohn Levon static void copy_statement(struct statement *src, struct statement *dst);
381f5207b7SJohn Levon 
dup_expression(struct expression * expr)391f5207b7SJohn Levon static struct expression * dup_expression(struct expression *expr)
401f5207b7SJohn Levon {
411f5207b7SJohn Levon 	struct expression *dup = alloc_expression(expr->pos, expr->type);
421f5207b7SJohn Levon 	*dup = *expr;
431f5207b7SJohn Levon 	return dup;
441f5207b7SJohn Levon }
451f5207b7SJohn Levon 
dup_statement(struct statement * stmt)461f5207b7SJohn Levon static struct statement * dup_statement(struct statement *stmt)
471f5207b7SJohn Levon {
481f5207b7SJohn Levon 	struct statement *dup = alloc_statement(stmt->pos, stmt->type);
491f5207b7SJohn Levon 	*dup = *stmt;
501f5207b7SJohn Levon 	return dup;
511f5207b7SJohn Levon }
521f5207b7SJohn Levon 
copy_symbol(struct position pos,struct symbol * sym)531f5207b7SJohn Levon static struct symbol *copy_symbol(struct position pos, struct symbol *sym)
541f5207b7SJohn Levon {
551f5207b7SJohn Levon 	if (!sym)
561f5207b7SJohn Levon 		return sym;
571f5207b7SJohn Levon 	if (sym->ctype.modifiers & (MOD_STATIC | MOD_EXTERN | MOD_TOPLEVEL | MOD_INLINE))
581f5207b7SJohn Levon 		return sym;
591f5207b7SJohn Levon 	if (!sym->replace) {
601f5207b7SJohn Levon 		warning(pos, "unreplaced symbol '%s'", show_ident(sym->ident));
611f5207b7SJohn Levon 		return sym;
621f5207b7SJohn Levon 	}
631f5207b7SJohn Levon 	return sym->replace;
641f5207b7SJohn Levon }
651f5207b7SJohn Levon 
copy_symbol_list(struct symbol_list * src)661f5207b7SJohn Levon static struct symbol_list *copy_symbol_list(struct symbol_list *src)
671f5207b7SJohn Levon {
681f5207b7SJohn Levon 	struct symbol_list *dst = NULL;
691f5207b7SJohn Levon 	struct symbol *sym;
701f5207b7SJohn Levon 
711f5207b7SJohn Levon 	FOR_EACH_PTR(src, sym) {
721f5207b7SJohn Levon 		struct symbol *newsym = copy_symbol(sym->pos, sym);
731f5207b7SJohn Levon 		add_symbol(&dst, newsym);
741f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sym);
751f5207b7SJohn Levon 	return dst;
761f5207b7SJohn Levon }
771f5207b7SJohn Levon 
copy_expression(struct expression * expr)781f5207b7SJohn Levon static struct expression * copy_expression(struct expression *expr)
791f5207b7SJohn Levon {
801f5207b7SJohn Levon 	if (!expr)
811f5207b7SJohn Levon 		return NULL;
821f5207b7SJohn Levon 
831f5207b7SJohn Levon 	switch (expr->type) {
841f5207b7SJohn Levon 	/*
851f5207b7SJohn Levon 	 * EXPR_SYMBOL is the interesting case, we may need to replace the
861f5207b7SJohn Levon 	 * symbol to the new copy.
871f5207b7SJohn Levon 	 */
881f5207b7SJohn Levon 	case EXPR_SYMBOL: {
891f5207b7SJohn Levon 		struct symbol *sym = copy_symbol(expr->pos, expr->symbol);
901f5207b7SJohn Levon 		if (sym == expr->symbol)
911f5207b7SJohn Levon 			break;
921f5207b7SJohn Levon 		expr = dup_expression(expr);
931f5207b7SJohn Levon 		expr->symbol = sym;
941f5207b7SJohn Levon 		break;
951f5207b7SJohn Levon 	}
961f5207b7SJohn Levon 
971f5207b7SJohn Levon 	/* Atomics, never change, just return the expression directly */
981f5207b7SJohn Levon 	case EXPR_VALUE:
991f5207b7SJohn Levon 	case EXPR_STRING:
1001f5207b7SJohn Levon 	case EXPR_FVALUE:
1011f5207b7SJohn Levon 	case EXPR_TYPE:
1021f5207b7SJohn Levon 		break;
1031f5207b7SJohn Levon 
1041f5207b7SJohn Levon 	/* Unops: check if the subexpression is unique */
1051f5207b7SJohn Levon 	case EXPR_PREOP:
1061f5207b7SJohn Levon 	case EXPR_POSTOP: {
1071f5207b7SJohn Levon 		struct expression *unop = copy_expression(expr->unop);
1081f5207b7SJohn Levon 		if (expr->unop == unop)
1091f5207b7SJohn Levon 			break;
1101f5207b7SJohn Levon 		expr = dup_expression(expr);
1111f5207b7SJohn Levon 		expr->unop = unop;
1121f5207b7SJohn Levon 		break;
1131f5207b7SJohn Levon 	}
1141f5207b7SJohn Levon 
1151f5207b7SJohn Levon 	case EXPR_SLICE: {
1161f5207b7SJohn Levon 		struct expression *base = copy_expression(expr->base);
1171f5207b7SJohn Levon 		expr = dup_expression(expr);
1181f5207b7SJohn Levon 		expr->base = base;
1191f5207b7SJohn Levon 		break;
1201f5207b7SJohn Levon 	}
1211f5207b7SJohn Levon 
1221f5207b7SJohn Levon 	/* Binops: copy left/right expressions */
1231f5207b7SJohn Levon 	case EXPR_BINOP:
1241f5207b7SJohn Levon 	case EXPR_COMMA:
1251f5207b7SJohn Levon 	case EXPR_COMPARE:
1261f5207b7SJohn Levon 	case EXPR_LOGICAL: {
1271f5207b7SJohn Levon 		struct expression *left = copy_expression(expr->left);
1281f5207b7SJohn Levon 		struct expression *right = copy_expression(expr->right);
1291f5207b7SJohn Levon 		if (left == expr->left && right == expr->right)
1301f5207b7SJohn Levon 			break;
1311f5207b7SJohn Levon 		expr = dup_expression(expr);
1321f5207b7SJohn Levon 		expr->left = left;
1331f5207b7SJohn Levon 		expr->right = right;
1341f5207b7SJohn Levon 		break;
1351f5207b7SJohn Levon 	}
1361f5207b7SJohn Levon 
1371f5207b7SJohn Levon 	case EXPR_ASSIGNMENT: {
1381f5207b7SJohn Levon 		struct expression *left = copy_expression(expr->left);
1391f5207b7SJohn Levon 		struct expression *right = copy_expression(expr->right);
1401f5207b7SJohn Levon 		if (expr->op == '=' && left == expr->left && right == expr->right)
1411f5207b7SJohn Levon 			break;
1421f5207b7SJohn Levon 		expr = dup_expression(expr);
1431f5207b7SJohn Levon 		expr->left = left;
1441f5207b7SJohn Levon 		expr->right = right;
1451f5207b7SJohn Levon 		break;
1461f5207b7SJohn Levon 	}
1471f5207b7SJohn Levon 
1481f5207b7SJohn Levon 	/* Dereference */
1491f5207b7SJohn Levon 	case EXPR_DEREF: {
1501f5207b7SJohn Levon 		struct expression *deref = copy_expression(expr->deref);
1511f5207b7SJohn Levon 		expr = dup_expression(expr);
1521f5207b7SJohn Levon 		expr->deref = deref;
1531f5207b7SJohn Levon 		break;
1541f5207b7SJohn Levon 	}
1551f5207b7SJohn Levon 
1561f5207b7SJohn Levon 	/* Cast/sizeof/__alignof__ */
1571f5207b7SJohn Levon 	case EXPR_CAST:
1581f5207b7SJohn Levon 		if (expr->cast_expression->type == EXPR_INITIALIZER) {
1591f5207b7SJohn Levon 			struct expression *cast = expr->cast_expression;
1601f5207b7SJohn Levon 			struct symbol *sym = expr->cast_type;
1611f5207b7SJohn Levon 			expr = dup_expression(expr);
1621f5207b7SJohn Levon 			expr->cast_expression = copy_expression(cast);
1631f5207b7SJohn Levon 			expr->cast_type = alloc_symbol(sym->pos, sym->type);
1641f5207b7SJohn Levon 			*expr->cast_type = *sym;
1651f5207b7SJohn Levon 			break;
1661f5207b7SJohn Levon 		}
1671f5207b7SJohn Levon 	case EXPR_FORCE_CAST:
1681f5207b7SJohn Levon 	case EXPR_IMPLIED_CAST:
1691f5207b7SJohn Levon 	case EXPR_SIZEOF:
1701f5207b7SJohn Levon 	case EXPR_PTRSIZEOF:
1711f5207b7SJohn Levon 	case EXPR_ALIGNOF: {
1721f5207b7SJohn Levon 		struct expression *cast = copy_expression(expr->cast_expression);
1731f5207b7SJohn Levon 		if (cast == expr->cast_expression)
1741f5207b7SJohn Levon 			break;
1751f5207b7SJohn Levon 		expr = dup_expression(expr);
1761f5207b7SJohn Levon 		expr->cast_expression = cast;
1771f5207b7SJohn Levon 		break;
1781f5207b7SJohn Levon 	}
1791f5207b7SJohn Levon 
1801f5207b7SJohn Levon 	/* Conditional expression */
1811f5207b7SJohn Levon 	case EXPR_SELECT:
1821f5207b7SJohn Levon 	case EXPR_CONDITIONAL: {
1831f5207b7SJohn Levon 		struct expression *cond = copy_expression(expr->conditional);
184*c85f09ccSJohn Levon 		struct expression *valt = copy_expression(expr->cond_true);
185*c85f09ccSJohn Levon 		struct expression *valf = copy_expression(expr->cond_false);
186*c85f09ccSJohn Levon 		if (cond == expr->conditional && valt == expr->cond_true && valf == expr->cond_false)
1871f5207b7SJohn Levon 			break;
1881f5207b7SJohn Levon 		expr = dup_expression(expr);
1891f5207b7SJohn Levon 		expr->conditional = cond;
190*c85f09ccSJohn Levon 		expr->cond_true = valt;
191*c85f09ccSJohn Levon 		expr->cond_false = valf;
1921f5207b7SJohn Levon 		break;
1931f5207b7SJohn Levon 	}
1941f5207b7SJohn Levon 
1951f5207b7SJohn Levon 	/* Statement expression */
1961f5207b7SJohn Levon 	case EXPR_STATEMENT: {
1971f5207b7SJohn Levon 		struct statement *stmt = alloc_statement(expr->pos, STMT_COMPOUND);
1981f5207b7SJohn Levon 		copy_statement(expr->statement, stmt);
1991f5207b7SJohn Levon 		expr = dup_expression(expr);
2001f5207b7SJohn Levon 		expr->statement = stmt;
2011f5207b7SJohn Levon 		break;
2021f5207b7SJohn Levon 	}
2031f5207b7SJohn Levon 
2041f5207b7SJohn Levon 	/* Call expression */
2051f5207b7SJohn Levon 	case EXPR_CALL: {
2061f5207b7SJohn Levon 		struct expression *fn = copy_expression(expr->fn);
2071f5207b7SJohn Levon 		struct expression_list *list = expr->args;
2081f5207b7SJohn Levon 		struct expression *arg;
2091f5207b7SJohn Levon 
2101f5207b7SJohn Levon 		expr = dup_expression(expr);
2111f5207b7SJohn Levon 		expr->fn = fn;
2121f5207b7SJohn Levon 		expr->args = NULL;
2131f5207b7SJohn Levon 		FOR_EACH_PTR(list, arg) {
2141f5207b7SJohn Levon 			add_expression(&expr->args, copy_expression(arg));
2151f5207b7SJohn Levon 		} END_FOR_EACH_PTR(arg);
2161f5207b7SJohn Levon 		break;
2171f5207b7SJohn Levon 	}
2181f5207b7SJohn Levon 
2191f5207b7SJohn Levon 	/* Initializer list statement */
2201f5207b7SJohn Levon 	case EXPR_INITIALIZER: {
2211f5207b7SJohn Levon 		struct expression_list *list = expr->expr_list;
2221f5207b7SJohn Levon 		struct expression *entry;
2231f5207b7SJohn Levon 		expr = dup_expression(expr);
2241f5207b7SJohn Levon 		expr->expr_list = NULL;
2251f5207b7SJohn Levon 		FOR_EACH_PTR(list, entry) {
2261f5207b7SJohn Levon 			add_expression(&expr->expr_list, copy_expression(entry));
2271f5207b7SJohn Levon 		} END_FOR_EACH_PTR(entry);
2281f5207b7SJohn Levon 		break;
2291f5207b7SJohn Levon 	}
2301f5207b7SJohn Levon 
2311f5207b7SJohn Levon 	/* Label in inline function - hmm. */
2321f5207b7SJohn Levon 	case EXPR_LABEL: {
2331f5207b7SJohn Levon 		struct symbol *label_symbol = copy_symbol(expr->pos, expr->label_symbol);
2341f5207b7SJohn Levon 		expr = dup_expression(expr);
2351f5207b7SJohn Levon 		expr->label_symbol = label_symbol;
2361f5207b7SJohn Levon 		break;
2371f5207b7SJohn Levon 	}
2381f5207b7SJohn Levon 
2391f5207b7SJohn Levon 	case EXPR_INDEX: {
2401f5207b7SJohn Levon 		struct expression *sub_expr = copy_expression(expr->idx_expression);
2411f5207b7SJohn Levon 		expr = dup_expression(expr);
2421f5207b7SJohn Levon 		expr->idx_expression = sub_expr;
2431f5207b7SJohn Levon 		break;
2441f5207b7SJohn Levon 	}
2451f5207b7SJohn Levon 
2461f5207b7SJohn Levon 	case EXPR_IDENTIFIER: {
2471f5207b7SJohn Levon 		struct expression *sub_expr = copy_expression(expr->ident_expression);
2481f5207b7SJohn Levon 		expr = dup_expression(expr);
2491f5207b7SJohn Levon 		expr->ident_expression = sub_expr;
2501f5207b7SJohn Levon 		break;
2511f5207b7SJohn Levon 	}
2521f5207b7SJohn Levon 
2531f5207b7SJohn Levon 	/* Position in initializer.. */
2541f5207b7SJohn Levon 	case EXPR_POS: {
2551f5207b7SJohn Levon 		struct expression *val = copy_expression(expr->init_expr);
2561f5207b7SJohn Levon 		expr = dup_expression(expr);
2571f5207b7SJohn Levon 		expr->init_expr = val;
2581f5207b7SJohn Levon 		break;
2591f5207b7SJohn Levon 	}
2601f5207b7SJohn Levon 	case EXPR_OFFSETOF: {
2611f5207b7SJohn Levon 		struct expression *val = copy_expression(expr->down);
2621f5207b7SJohn Levon 		if (expr->op == '.') {
2631f5207b7SJohn Levon 			if (expr->down != val) {
2641f5207b7SJohn Levon 				expr = dup_expression(expr);
2651f5207b7SJohn Levon 				expr->down = val;
2661f5207b7SJohn Levon 			}
2671f5207b7SJohn Levon 		} else {
2681f5207b7SJohn Levon 			struct expression *idx = copy_expression(expr->index);
2691f5207b7SJohn Levon 			if (expr->down != val || expr->index != idx) {
2701f5207b7SJohn Levon 				expr = dup_expression(expr);
2711f5207b7SJohn Levon 				expr->down = val;
2721f5207b7SJohn Levon 				expr->index = idx;
2731f5207b7SJohn Levon 			}
2741f5207b7SJohn Levon 		}
2751f5207b7SJohn Levon 		break;
2761f5207b7SJohn Levon 	}
277*c85f09ccSJohn Levon 	case EXPR_ASM_OPERAND: {
278*c85f09ccSJohn Levon 		expr = dup_expression(expr);
279*c85f09ccSJohn Levon 		expr->constraint = copy_expression(expr->constraint);
280*c85f09ccSJohn Levon 		expr->expr = copy_expression(expr->expr);
281*c85f09ccSJohn Levon 		break;
282*c85f09ccSJohn Levon 	}
2831f5207b7SJohn Levon 	default:
2841f5207b7SJohn Levon 		warning(expr->pos, "trying to copy expression type %d", expr->type);
2851f5207b7SJohn Levon 	}
2861f5207b7SJohn Levon 	return expr;
2871f5207b7SJohn Levon }
2881f5207b7SJohn Levon 
copy_asm_constraints(struct expression_list * in)2891f5207b7SJohn Levon static struct expression_list *copy_asm_constraints(struct expression_list *in)
2901f5207b7SJohn Levon {
2911f5207b7SJohn Levon 	struct expression_list *out = NULL;
2921f5207b7SJohn Levon 	struct expression *expr;
2931f5207b7SJohn Levon 
2941f5207b7SJohn Levon 	FOR_EACH_PTR(in, expr) {
295*c85f09ccSJohn Levon 		add_expression(&out, copy_expression(expr));
2961f5207b7SJohn Levon 	} END_FOR_EACH_PTR(expr);
2971f5207b7SJohn Levon 	return out;
2981f5207b7SJohn Levon }
2991f5207b7SJohn Levon 
set_replace(struct symbol * old,struct symbol * new)3001f5207b7SJohn Levon static void set_replace(struct symbol *old, struct symbol *new)
3011f5207b7SJohn Levon {
3021f5207b7SJohn Levon 	new->replace = old;
3031f5207b7SJohn Levon 	old->replace = new;
3041f5207b7SJohn Levon }
3051f5207b7SJohn Levon 
unset_replace(struct symbol * sym)3061f5207b7SJohn Levon static void unset_replace(struct symbol *sym)
3071f5207b7SJohn Levon {
3081f5207b7SJohn Levon 	struct symbol *r = sym->replace;
3091f5207b7SJohn Levon 	if (!r) {
3101f5207b7SJohn Levon 		warning(sym->pos, "symbol '%s' not replaced?", show_ident(sym->ident));
3111f5207b7SJohn Levon 		return;
3121f5207b7SJohn Levon 	}
3131f5207b7SJohn Levon 	r->replace = NULL;
3141f5207b7SJohn Levon 	sym->replace = NULL;
3151f5207b7SJohn Levon }
3161f5207b7SJohn Levon 
unset_replace_list(struct symbol_list * list)3171f5207b7SJohn Levon static void unset_replace_list(struct symbol_list *list)
3181f5207b7SJohn Levon {
3191f5207b7SJohn Levon 	struct symbol *sym;
3201f5207b7SJohn Levon 	FOR_EACH_PTR(list, sym) {
3211f5207b7SJohn Levon 		unset_replace(sym);
3221f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sym);
3231f5207b7SJohn Levon }
3241f5207b7SJohn Levon 
copy_one_statement(struct statement * stmt)3251f5207b7SJohn Levon static struct statement *copy_one_statement(struct statement *stmt)
3261f5207b7SJohn Levon {
3271f5207b7SJohn Levon 	if (!stmt)
3281f5207b7SJohn Levon 		return NULL;
3291f5207b7SJohn Levon 	switch(stmt->type) {
3301f5207b7SJohn Levon 	case STMT_NONE:
3311f5207b7SJohn Levon 		break;
3321f5207b7SJohn Levon 	case STMT_DECLARATION: {
3331f5207b7SJohn Levon 		struct symbol *sym;
3341f5207b7SJohn Levon 		struct statement *newstmt = dup_statement(stmt);
3351f5207b7SJohn Levon 		newstmt->declaration = NULL;
3361f5207b7SJohn Levon 		FOR_EACH_PTR(stmt->declaration, sym) {
3371f5207b7SJohn Levon 			struct symbol *newsym = copy_symbol(stmt->pos, sym);
3381f5207b7SJohn Levon 			if (newsym != sym)
3391f5207b7SJohn Levon 				newsym->initializer = copy_expression(sym->initializer);
3401f5207b7SJohn Levon 			add_symbol(&newstmt->declaration, newsym);
3411f5207b7SJohn Levon 		} END_FOR_EACH_PTR(sym);
3421f5207b7SJohn Levon 		stmt = newstmt;
3431f5207b7SJohn Levon 		break;
3441f5207b7SJohn Levon 	}
3451f5207b7SJohn Levon 	case STMT_CONTEXT:
3461f5207b7SJohn Levon 	case STMT_EXPRESSION: {
3471f5207b7SJohn Levon 		struct expression *expr = copy_expression(stmt->expression);
3481f5207b7SJohn Levon 		if (expr == stmt->expression)
3491f5207b7SJohn Levon 			break;
3501f5207b7SJohn Levon 		stmt = dup_statement(stmt);
3511f5207b7SJohn Levon 		stmt->expression = expr;
3521f5207b7SJohn Levon 		break;
3531f5207b7SJohn Levon 	}
3541f5207b7SJohn Levon 	case STMT_RANGE: {
3551f5207b7SJohn Levon 		struct expression *expr = copy_expression(stmt->range_expression);
3561f5207b7SJohn Levon 		if (expr == stmt->expression)
3571f5207b7SJohn Levon 			break;
3581f5207b7SJohn Levon 		stmt = dup_statement(stmt);
3591f5207b7SJohn Levon 		stmt->range_expression = expr;
3601f5207b7SJohn Levon 		break;
3611f5207b7SJohn Levon 	}
3621f5207b7SJohn Levon 	case STMT_COMPOUND: {
3631f5207b7SJohn Levon 		struct statement *new = alloc_statement(stmt->pos, STMT_COMPOUND);
3641f5207b7SJohn Levon 		copy_statement(stmt, new);
3651f5207b7SJohn Levon 		stmt = new;
3661f5207b7SJohn Levon 		break;
3671f5207b7SJohn Levon 	}
3681f5207b7SJohn Levon 	case STMT_IF: {
3691f5207b7SJohn Levon 		struct expression *cond = stmt->if_conditional;
370*c85f09ccSJohn Levon 		struct statement *valt = stmt->if_true;
371*c85f09ccSJohn Levon 		struct statement *valf = stmt->if_false;
3721f5207b7SJohn Levon 
3731f5207b7SJohn Levon 		cond = copy_expression(cond);
374*c85f09ccSJohn Levon 		valt = copy_one_statement(valt);
375*c85f09ccSJohn Levon 		valf = copy_one_statement(valf);
3761f5207b7SJohn Levon 		if (stmt->if_conditional == cond &&
377*c85f09ccSJohn Levon 		    stmt->if_true == valt &&
378*c85f09ccSJohn Levon 		    stmt->if_false == valf)
3791f5207b7SJohn Levon 			break;
3801f5207b7SJohn Levon 		stmt = dup_statement(stmt);
3811f5207b7SJohn Levon 		stmt->if_conditional = cond;
382*c85f09ccSJohn Levon 		stmt->if_true = valt;
383*c85f09ccSJohn Levon 		stmt->if_false = valf;
3841f5207b7SJohn Levon 		break;
3851f5207b7SJohn Levon 	}
3861f5207b7SJohn Levon 	case STMT_RETURN: {
3871f5207b7SJohn Levon 		struct expression *retval = copy_expression(stmt->ret_value);
3881f5207b7SJohn Levon 		struct symbol *sym = copy_symbol(stmt->pos, stmt->ret_target);
3891f5207b7SJohn Levon 
3901f5207b7SJohn Levon 		stmt = dup_statement(stmt);
3911f5207b7SJohn Levon 		stmt->ret_value = retval;
3921f5207b7SJohn Levon 		stmt->ret_target = sym;
3931f5207b7SJohn Levon 		break;
3941f5207b7SJohn Levon 	}
3951f5207b7SJohn Levon 	case STMT_CASE: {
3961f5207b7SJohn Levon 		stmt = dup_statement(stmt);
3971f5207b7SJohn Levon 		stmt->case_label = copy_symbol(stmt->pos, stmt->case_label);
3981f5207b7SJohn Levon 		stmt->case_label->stmt = stmt;
3991f5207b7SJohn Levon 		stmt->case_expression = copy_expression(stmt->case_expression);
4001f5207b7SJohn Levon 		stmt->case_to = copy_expression(stmt->case_to);
4011f5207b7SJohn Levon 		stmt->case_statement = copy_one_statement(stmt->case_statement);
4021f5207b7SJohn Levon 		break;
4031f5207b7SJohn Levon 	}
4041f5207b7SJohn Levon 	case STMT_SWITCH: {
4051f5207b7SJohn Levon 		struct symbol *switch_break = copy_symbol(stmt->pos, stmt->switch_break);
4061f5207b7SJohn Levon 		struct symbol *switch_case = copy_symbol(stmt->pos, stmt->switch_case);
4071f5207b7SJohn Levon 		struct expression *expr = copy_expression(stmt->switch_expression);
4081f5207b7SJohn Levon 		struct statement *switch_stmt = copy_one_statement(stmt->switch_statement);
4091f5207b7SJohn Levon 
4101f5207b7SJohn Levon 		stmt = dup_statement(stmt);
4111f5207b7SJohn Levon 		switch_case->symbol_list = copy_symbol_list(switch_case->symbol_list);
4121f5207b7SJohn Levon 		stmt->switch_break = switch_break;
4131f5207b7SJohn Levon 		stmt->switch_case = switch_case;
4141f5207b7SJohn Levon 		stmt->switch_expression = expr;
4151f5207b7SJohn Levon 		stmt->switch_statement = switch_stmt;
4161f5207b7SJohn Levon 		break;
4171f5207b7SJohn Levon 	}
4181f5207b7SJohn Levon 	case STMT_ITERATOR: {
4191f5207b7SJohn Levon 		stmt = dup_statement(stmt);
4201f5207b7SJohn Levon 		stmt->iterator_break = copy_symbol(stmt->pos, stmt->iterator_break);
4211f5207b7SJohn Levon 		stmt->iterator_continue = copy_symbol(stmt->pos, stmt->iterator_continue);
4221f5207b7SJohn Levon 		stmt->iterator_syms = copy_symbol_list(stmt->iterator_syms);
4231f5207b7SJohn Levon 
4241f5207b7SJohn Levon 		stmt->iterator_pre_statement = copy_one_statement(stmt->iterator_pre_statement);
4251f5207b7SJohn Levon 		stmt->iterator_pre_condition = copy_expression(stmt->iterator_pre_condition);
4261f5207b7SJohn Levon 
4271f5207b7SJohn Levon 		stmt->iterator_statement = copy_one_statement(stmt->iterator_statement);
4281f5207b7SJohn Levon 
4291f5207b7SJohn Levon 		stmt->iterator_post_statement = copy_one_statement(stmt->iterator_post_statement);
4301f5207b7SJohn Levon 		stmt->iterator_post_condition = copy_expression(stmt->iterator_post_condition);
4311f5207b7SJohn Levon 		break;
4321f5207b7SJohn Levon 	}
4331f5207b7SJohn Levon 	case STMT_LABEL: {
4341f5207b7SJohn Levon 		stmt = dup_statement(stmt);
4351f5207b7SJohn Levon 		stmt->label_identifier = copy_symbol(stmt->pos, stmt->label_identifier);
4361f5207b7SJohn Levon 		stmt->label_statement = copy_one_statement(stmt->label_statement);
4371f5207b7SJohn Levon 		break;
4381f5207b7SJohn Levon 	}
4391f5207b7SJohn Levon 	case STMT_GOTO: {
4401f5207b7SJohn Levon 		stmt = dup_statement(stmt);
4411f5207b7SJohn Levon 		stmt->goto_label = copy_symbol(stmt->pos, stmt->goto_label);
4421f5207b7SJohn Levon 		stmt->goto_expression = copy_expression(stmt->goto_expression);
4431f5207b7SJohn Levon 		stmt->target_list = copy_symbol_list(stmt->target_list);
4441f5207b7SJohn Levon 		break;
4451f5207b7SJohn Levon 	}
4461f5207b7SJohn Levon 	case STMT_ASM: {
4471f5207b7SJohn Levon 		stmt = dup_statement(stmt);
4481f5207b7SJohn Levon 		stmt->asm_inputs = copy_asm_constraints(stmt->asm_inputs);
4491f5207b7SJohn Levon 		stmt->asm_outputs = copy_asm_constraints(stmt->asm_outputs);
4501f5207b7SJohn Levon 		/* no need to dup "clobbers", since they are all constant strings */
4511f5207b7SJohn Levon 		break;
4521f5207b7SJohn Levon 	}
4531f5207b7SJohn Levon 	default:
4541f5207b7SJohn Levon 		warning(stmt->pos, "trying to copy statement type %d", stmt->type);
4551f5207b7SJohn Levon 		break;
4561f5207b7SJohn Levon 	}
4571f5207b7SJohn Levon 	return stmt;
4581f5207b7SJohn Levon }
4591f5207b7SJohn Levon 
4601f5207b7SJohn Levon /*
4611f5207b7SJohn Levon  * Copy a statement tree from 'src' to 'dst', where both
4621f5207b7SJohn Levon  * source and destination are of type STMT_COMPOUND.
4631f5207b7SJohn Levon  *
4641f5207b7SJohn Levon  * We do this for the tree-level inliner.
4651f5207b7SJohn Levon  *
4661f5207b7SJohn Levon  * This doesn't do the symbol replacement right: it's not
4671f5207b7SJohn Levon  * re-entrant.
4681f5207b7SJohn Levon  */
copy_statement(struct statement * src,struct statement * dst)469*c85f09ccSJohn Levon static void copy_statement(struct statement *src, struct statement *dst)
4701f5207b7SJohn Levon {
4711f5207b7SJohn Levon 	struct statement *stmt;
4721f5207b7SJohn Levon 
4731f5207b7SJohn Levon 	FOR_EACH_PTR(src->stmts, stmt) {
4741f5207b7SJohn Levon 		add_statement(&dst->stmts, copy_one_statement(stmt));
4751f5207b7SJohn Levon 	} END_FOR_EACH_PTR(stmt);
4761f5207b7SJohn Levon 	dst->args = copy_one_statement(src->args);
4771f5207b7SJohn Levon 	dst->ret = copy_symbol(src->pos, src->ret);
4781f5207b7SJohn Levon 	dst->inline_fn = src->inline_fn;
4791f5207b7SJohn Levon }
4801f5207b7SJohn Levon 
create_copy_symbol(struct symbol * orig)4811f5207b7SJohn Levon static struct symbol *create_copy_symbol(struct symbol *orig)
4821f5207b7SJohn Levon {
4831f5207b7SJohn Levon 	struct symbol *sym = orig;
4841f5207b7SJohn Levon 	if (orig) {
4851f5207b7SJohn Levon 		sym = alloc_symbol(orig->pos, orig->type);
4861f5207b7SJohn Levon 		*sym = *orig;
4871f5207b7SJohn Levon 		sym->bb_target = NULL;
4881f5207b7SJohn Levon 		sym->pseudo = NULL;
4891f5207b7SJohn Levon 		set_replace(orig, sym);
4901f5207b7SJohn Levon 		orig = sym;
4911f5207b7SJohn Levon 	}
4921f5207b7SJohn Levon 	return orig;
4931f5207b7SJohn Levon }
4941f5207b7SJohn Levon 
create_symbol_list(struct symbol_list * src)4951f5207b7SJohn Levon static struct symbol_list *create_symbol_list(struct symbol_list *src)
4961f5207b7SJohn Levon {
4971f5207b7SJohn Levon 	struct symbol_list *dst = NULL;
4981f5207b7SJohn Levon 	struct symbol *sym;
4991f5207b7SJohn Levon 
5001f5207b7SJohn Levon 	FOR_EACH_PTR(src, sym) {
5011f5207b7SJohn Levon 		struct symbol *newsym = create_copy_symbol(sym);
5021f5207b7SJohn Levon 		add_symbol(&dst, newsym);
5031f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sym);
5041f5207b7SJohn Levon 	return dst;
5051f5207b7SJohn Levon }
5061f5207b7SJohn Levon 
inline_function(struct expression * expr,struct symbol * sym)5071f5207b7SJohn Levon int inline_function(struct expression *expr, struct symbol *sym)
5081f5207b7SJohn Levon {
5091f5207b7SJohn Levon 	struct symbol_list * fn_symbol_list;
5101f5207b7SJohn Levon 	struct symbol *fn = sym->ctype.base_type;
5111f5207b7SJohn Levon 	struct expression_list *arg_list = expr->args;
5121f5207b7SJohn Levon 	struct statement *stmt = alloc_statement(expr->pos, STMT_COMPOUND);
5131f5207b7SJohn Levon 	struct symbol_list *name_list, *arg_decl;
5141f5207b7SJohn Levon 	struct symbol *name;
5151f5207b7SJohn Levon 	struct expression *arg;
5161f5207b7SJohn Levon 
5171f5207b7SJohn Levon 	if (!fn->inline_stmt) {
5181f5207b7SJohn Levon 		sparse_error(fn->pos, "marked inline, but without a definition");
5191f5207b7SJohn Levon 		return 0;
5201f5207b7SJohn Levon 	}
5211f5207b7SJohn Levon 	if (fn->expanding)
5221f5207b7SJohn Levon 		return 0;
5231f5207b7SJohn Levon 
5241f5207b7SJohn Levon 	fn->expanding = 1;
5251f5207b7SJohn Levon 
5261f5207b7SJohn Levon 	name_list = fn->arguments;
5271f5207b7SJohn Levon 
5281f5207b7SJohn Levon 	expr->type = EXPR_STATEMENT;
5291f5207b7SJohn Levon 	expr->statement = stmt;
5301f5207b7SJohn Levon 	expr->ctype = fn->ctype.base_type;
5311f5207b7SJohn Levon 
5321f5207b7SJohn Levon 	fn_symbol_list = create_symbol_list(sym->inline_symbol_list);
5331f5207b7SJohn Levon 
5341f5207b7SJohn Levon 	arg_decl = NULL;
5351f5207b7SJohn Levon 	PREPARE_PTR_LIST(name_list, name);
5361f5207b7SJohn Levon 	FOR_EACH_PTR(arg_list, arg) {
5371f5207b7SJohn Levon 		struct symbol *a = alloc_symbol(arg->pos, SYM_NODE);
5381f5207b7SJohn Levon 
5391f5207b7SJohn Levon 		a->ctype.base_type = arg->ctype;
5401f5207b7SJohn Levon 		if (name) {
5411f5207b7SJohn Levon 			*a = *name;
5421f5207b7SJohn Levon 			set_replace(name, a);
5431f5207b7SJohn Levon 			add_symbol(&fn_symbol_list, a);
5441f5207b7SJohn Levon 		}
5451f5207b7SJohn Levon 		a->initializer = arg;
5461f5207b7SJohn Levon 		add_symbol(&arg_decl, a);
5471f5207b7SJohn Levon 
5481f5207b7SJohn Levon 		NEXT_PTR_LIST(name);
5491f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
5501f5207b7SJohn Levon 	FINISH_PTR_LIST(name);
5511f5207b7SJohn Levon 
5521f5207b7SJohn Levon 	copy_statement(fn->inline_stmt, stmt);
5531f5207b7SJohn Levon 
5541f5207b7SJohn Levon 	if (arg_decl) {
5551f5207b7SJohn Levon 		struct statement *decl = alloc_statement(expr->pos, STMT_DECLARATION);
5561f5207b7SJohn Levon 		decl->declaration = arg_decl;
5571f5207b7SJohn Levon 		stmt->args = decl;
5581f5207b7SJohn Levon 	}
5591f5207b7SJohn Levon 	stmt->inline_fn = sym;
5601f5207b7SJohn Levon 
5611f5207b7SJohn Levon 	unset_replace_list(fn_symbol_list);
5621f5207b7SJohn Levon 
5631f5207b7SJohn Levon 	evaluate_statement(stmt);
5641f5207b7SJohn Levon 
5651f5207b7SJohn Levon 	fn->expanding = 0;
5661f5207b7SJohn Levon 	return 1;
5671f5207b7SJohn Levon }
5681f5207b7SJohn Levon 
uninline(struct symbol * sym)5691f5207b7SJohn Levon void uninline(struct symbol *sym)
5701f5207b7SJohn Levon {
5711f5207b7SJohn Levon 	struct symbol *fn = sym->ctype.base_type;
5721f5207b7SJohn Levon 	struct symbol_list *arg_list = fn->arguments;
5731f5207b7SJohn Levon 	struct symbol *p;
5741f5207b7SJohn Levon 
5751f5207b7SJohn Levon 	sym->symbol_list = create_symbol_list(sym->inline_symbol_list);
5761f5207b7SJohn Levon 	FOR_EACH_PTR(arg_list, p) {
5771f5207b7SJohn Levon 		p->replace = p;
5781f5207b7SJohn Levon 	} END_FOR_EACH_PTR(p);
5791f5207b7SJohn Levon 	fn->stmt = alloc_statement(fn->pos, STMT_COMPOUND);
5801f5207b7SJohn Levon 	copy_statement(fn->inline_stmt, fn->stmt);
5811f5207b7SJohn Levon 	unset_replace_list(sym->symbol_list);
5821f5207b7SJohn Levon 	unset_replace_list(arg_list);
5831f5207b7SJohn Levon }
584