Fix up function inlining:
[smatch.git] / inline.c
bloba6dc64dd3862484d5649f93124b91a158080443d
1 /*
2 * Sparse - a semantic source parser.
4 * Copyright (C) 2003 Transmeta Corp.
6 * Licensed under the Open Software License version 1.1
7 */
9 #include <stdlib.h>
10 #include <stdio.h>
12 #include "lib.h"
13 #include "token.h"
14 #include "parse.h"
15 #include "symbol.h"
16 #include "expression.h"
18 static struct expression * dup_expression(struct expression *expr)
20 struct expression *dup = alloc_expression(expr->pos, expr->type);
21 *dup = *expr;
22 return dup;
25 static struct statement * dup_statement(struct statement *stmt)
27 struct statement *dup = alloc_statement(stmt->pos, stmt->type);
28 *dup = *stmt;
29 return dup;
32 static struct symbol *copy_symbol(struct position pos, struct symbol *sym)
34 if (!sym)
35 return sym;
36 if (sym->ctype.modifiers & (MOD_STATIC | MOD_EXTERN | MOD_TOPLEVEL | MOD_INLINE))
37 return sym;
38 if (!sym->replace) {
39 warn(pos, "unreplaced symbol '%s'", show_ident(sym->ident));
40 return sym;
42 return sym->replace;
45 static struct symbol_list *copy_symbol_list(struct symbol_list *src)
47 struct symbol_list *dst = NULL;
48 struct symbol *sym;
50 FOR_EACH_PTR(src, sym) {
51 struct symbol *newsym = copy_symbol(sym->pos, sym);
52 add_symbol(&dst, newsym);
53 } END_FOR_EACH_PTR;
54 return dst;
57 static struct expression * copy_expression(struct expression *expr)
59 if (!expr)
60 return NULL;
62 switch (expr->type) {
64 * EXPR_SYMBOL is the interesting case, we may need to replace the
65 * symbol to the new copy.
67 case EXPR_SYMBOL: {
68 struct symbol *sym = copy_symbol(expr->pos, expr->symbol);
69 if (sym == expr->symbol)
70 break;
71 expr = dup_expression(expr);
72 expr->symbol = sym;
73 break;
76 /* Atomics, never change, just return the expression directly */
77 case EXPR_VALUE:
78 case EXPR_STRING:
79 break;
81 /* Unops: check if the subexpression is unique */
82 case EXPR_PREOP:
83 case EXPR_POSTOP: {
84 struct expression *unop = copy_expression(expr->unop);
85 if (expr->unop == unop)
86 break;
87 expr = dup_expression(expr);
88 expr->unop = unop;
89 break;
92 /* Binops: copy left/right expressions */
93 case EXPR_BINOP:
94 case EXPR_COMMA:
95 case EXPR_COMPARE:
96 case EXPR_LOGICAL:
97 case EXPR_ASSIGNMENT: {
98 struct expression *left = copy_expression(expr->left);
99 struct expression *right = copy_expression(expr->right);
100 if (left == expr->left && right == expr->right)
101 break;
102 expr = dup_expression(expr);
103 expr->left = left;
104 expr->right = right;
105 break;
108 /* Dereference */
109 case EXPR_DEREF: {
110 struct expression *deref = copy_expression(expr->deref);
111 if (deref == expr->deref)
112 break;
113 expr = dup_expression(expr);
114 expr->deref = deref;
115 break;
118 /* Cast/sizeof */
119 case EXPR_CAST:
120 case EXPR_SIZEOF: {
121 struct expression *cast = copy_expression(expr->cast_expression);
122 if (cast == expr->cast_expression)
123 break;
124 expr = dup_expression(expr);
125 expr->cast_expression = cast;
126 break;
129 /* Conditional expression */
130 case EXPR_CONDITIONAL: {
131 struct expression *cond = copy_expression(expr->conditional);
132 struct expression *true = copy_expression(expr->cond_true);
133 struct expression *false = copy_expression(expr->cond_false);
134 if (cond == expr->conditional && true == expr->cond_true && false == expr->cond_false)
135 break;
136 expr = dup_expression(expr);
137 expr->conditional = cond;
138 expr->cond_true = true;
139 expr->cond_false = false;
140 break;
143 /* Statement expression */
144 case EXPR_STATEMENT: {
145 struct statement *stmt = alloc_statement(expr->pos, STMT_COMPOUND);
146 copy_statement(expr->statement, stmt);
147 expr = dup_expression(expr);
148 expr->statement = stmt;
149 break;
152 /* Call expression */
153 case EXPR_CALL: {
154 struct expression *fn = copy_expression(expr->fn);
155 struct expression_list *list = expr->args;
156 struct expression *arg;
158 expr = dup_expression(expr);
159 expr->fn = fn;
160 expr->args = NULL;
161 FOR_EACH_PTR(list, arg) {
162 add_expression(&expr->args, copy_expression(arg));
163 } END_FOR_EACH_PTR;
164 break;
167 /* Initializer list statement */
168 case EXPR_INITIALIZER: {
169 struct expression_list *list = expr->expr_list;
170 struct expression *entry;
171 expr = dup_expression(expr);
172 expr->expr_list = NULL;
173 FOR_EACH_PTR(list, entry) {
174 add_expression(&expr->expr_list, copy_expression(entry));
175 } END_FOR_EACH_PTR;
176 break;
179 default:
180 if (verbose)
181 warn(expr->pos, "trying to copy expression type %d", expr->type);
183 return expr;
186 void set_replace(struct symbol *old, struct symbol *new)
188 new->replace = old;
189 old->replace = new;
192 void unset_replace(struct symbol *sym)
194 struct symbol *r = sym->replace;
195 if (!r) {
196 warn(sym->pos, "symbol '%s' not replaced?", show_ident(sym->ident));
197 return;
199 r->replace = NULL;
200 sym->replace = NULL;
203 static void unset_replace_list(struct symbol_list *list)
205 struct symbol *sym;
206 FOR_EACH_PTR(list, sym) {
207 unset_replace(sym);
208 } END_FOR_EACH_PTR;
211 static struct statement *copy_one_statement(struct statement *stmt)
213 if (!stmt)
214 return NULL;
215 switch(stmt->type) {
216 case STMT_NONE:
217 break;
218 case STMT_EXPRESSION: {
219 struct expression *expr = copy_expression(stmt->expression);
220 if (expr == stmt->expression)
221 break;
222 stmt = dup_statement(stmt);
223 stmt->expression = expr;
224 break;
226 case STMT_COMPOUND: {
227 struct statement *new = alloc_statement(stmt->pos, STMT_COMPOUND);
228 copy_statement(stmt, new);
229 stmt = new;
230 break;
232 case STMT_IF: {
233 struct expression *cond = stmt->if_conditional;
234 struct statement *true = stmt->if_true;
235 struct statement *false = stmt->if_false;
237 cond = copy_expression(cond);
238 true = copy_one_statement(true);
239 false = copy_one_statement(false);
240 if (stmt->if_conditional == cond &&
241 stmt->if_true == true &&
242 stmt->if_false == false)
243 break;
244 stmt = dup_statement(stmt);
245 stmt->if_conditional = cond;
246 stmt->if_true = true;
247 stmt->if_false = false;
248 break;
250 case STMT_RETURN: {
251 struct expression *retval = copy_expression(stmt->ret_value);
252 struct symbol *sym = copy_symbol(stmt->pos, stmt->ret_target);
254 stmt = dup_statement(stmt);
255 stmt->ret_value = retval;
256 stmt->ret_target = sym;
257 break;
259 case STMT_CASE: {
260 stmt = dup_statement(stmt);
261 stmt->case_label = copy_symbol(stmt->pos, stmt->case_label);
262 stmt->case_expression = copy_expression(stmt->case_expression);
263 stmt->case_to = copy_expression(stmt->case_to);
264 stmt->case_statement = copy_one_statement(stmt->case_statement);
265 break;
267 case STMT_SWITCH: {
268 struct symbol *switch_break = copy_symbol(stmt->pos, stmt->switch_break);
269 struct symbol *switch_case = copy_symbol(stmt->pos, stmt->switch_case);
270 struct expression *expr = copy_expression(stmt->switch_expression);
271 struct statement *switch_stmt = copy_one_statement(stmt->switch_statement);
272 stmt = dup_statement(stmt);
273 stmt->switch_break = switch_break;
274 stmt->switch_case = switch_case;
275 stmt->switch_expression = expr;
276 stmt->switch_statement = switch_stmt;
277 break;
279 case STMT_ITERATOR: {
280 stmt = dup_statement(stmt);
281 stmt->iterator_break = copy_symbol(stmt->pos, stmt->iterator_break);
282 stmt->iterator_continue = copy_symbol(stmt->pos, stmt->iterator_continue);
283 stmt->iterator_syms = copy_symbol_list(stmt->iterator_syms);
285 stmt->iterator_pre_statement = copy_one_statement(stmt->iterator_pre_statement);
286 stmt->iterator_pre_condition = copy_expression(stmt->iterator_pre_condition);
288 stmt->iterator_statement = copy_one_statement(stmt->iterator_statement);
290 stmt->iterator_post_statement = copy_one_statement(stmt->iterator_post_statement);
291 stmt->iterator_post_condition = copy_expression(stmt->iterator_post_condition);
292 break;
294 case STMT_LABEL: {
295 stmt = dup_statement(stmt);
296 stmt->label_identifier = copy_symbol(stmt->pos, stmt->label_identifier);
297 stmt->label_statement = copy_one_statement(stmt->label_statement);
298 break;
300 case STMT_GOTO: {
301 /* FIXME! */
302 break;
304 case STMT_ASM: {
305 /* FIXME! */
306 break;
308 default:
309 if (verbose)
310 warn(stmt->pos, "trying to copy statement type %d", stmt->type);
311 break;
313 return stmt;
317 * Copy a stateemnt tree from 'src' to 'dst', where both
318 * source and destination are of type STMT_COMPOUND.
320 * We do this for the tree-level inliner.
322 * This doesn't do the symbol replacement right: it's not
323 * re-entrant.
325 void copy_statement(struct statement *src, struct statement *dst)
327 struct statement *stmt;
328 struct symbol *sym;
330 FOR_EACH_PTR(src->syms, sym) {
331 struct symbol *newsym = copy_symbol(src->pos, sym);
332 newsym->initializer = copy_expression(sym->initializer);
333 add_symbol(&dst->syms, newsym);
334 } END_FOR_EACH_PTR;
336 FOR_EACH_PTR(src->stmts, stmt) {
337 add_statement(&dst->stmts, copy_one_statement(stmt));
338 } END_FOR_EACH_PTR;
340 dst->ret = copy_symbol(src->pos, src->ret);
343 static struct symbol *create_copy_symbol(struct symbol *orig)
345 struct symbol *sym = orig;
346 if (orig) {
347 sym = alloc_symbol(orig->pos, orig->type);
348 sym->ctype = orig->ctype;
349 sym->initializer = NULL;
350 set_replace(orig, sym);
352 return orig;
355 static struct symbol_list *create_symbol_list(struct symbol_list *src)
357 struct symbol_list *dst = NULL;
358 struct symbol *sym;
360 FOR_EACH_PTR(src, sym) {
361 struct symbol *newsym = create_copy_symbol(sym);
362 add_symbol(&dst, newsym);
363 } END_FOR_EACH_PTR;
364 return dst;
367 int inline_function(struct expression *expr, struct symbol *sym)
369 struct symbol_list * fn_symbol_list;
370 struct symbol *fn = sym->ctype.base_type;
371 struct expression_list *arg_list = expr->args;
372 struct statement *stmt = alloc_statement(expr->pos, STMT_COMPOUND);
373 struct symbol_list *name_list;
374 struct symbol *name;
375 struct expression *arg;
377 if (!fn->stmt) {
378 warn(fn->pos, "marked inline, but without a definition");
379 return 0;
381 name_list = fn->arguments;
383 stmt = alloc_statement(expr->pos, STMT_COMPOUND);
385 expr->type = EXPR_STATEMENT;
386 expr->statement = stmt;
387 expr->ctype = fn->ctype.base_type;
389 fn_symbol_list = create_symbol_list(sym->symbol_list);
391 PREPARE_PTR_LIST(name_list, name);
392 FOR_EACH_PTR(arg_list, arg) {
393 struct symbol *a = alloc_symbol(arg->pos, SYM_NODE);
395 a->ctype.base_type = arg->ctype;
396 if (name) {
397 a->ident = name->ident;
398 a->ctype = name->ctype;
399 set_replace(name, a);
400 add_symbol(&fn_symbol_list, a);
402 a->initializer = arg;
403 add_symbol(&stmt->syms, a);
405 NEXT_PTR_LIST(name);
406 } END_FOR_EACH_PTR;
407 FINISH_PTR_LIST(name);
409 copy_statement(fn->stmt, stmt);
411 unset_replace_list(fn_symbol_list);
413 evaluate_statement(stmt);
415 return 1;