Make our "__builtin_va_arg()" thing a bit closer to real.
[smatch.git] / inline.c
blob9d5774edaca5373dad0b00876570b078733b1d22
1 /*
2 * Sparse - a semantic source parser.
4 * Copyright (C) 2003 Transmeta Corp.
5 * 2003 Linus Torvalds
7 * Licensed under the Open Software License version 1.1
8 */
10 #include <stdlib.h>
11 #include <stdio.h>
13 #include "lib.h"
14 #include "token.h"
15 #include "parse.h"
16 #include "symbol.h"
17 #include "expression.h"
19 static struct expression * dup_expression(struct expression *expr)
21 struct expression *dup = alloc_expression(expr->pos, expr->type);
22 *dup = *expr;
23 return dup;
26 static struct statement * dup_statement(struct statement *stmt)
28 struct statement *dup = alloc_statement(stmt->pos, stmt->type);
29 *dup = *stmt;
30 return dup;
33 static struct symbol *copy_symbol(struct position pos, struct symbol *sym)
35 if (!sym)
36 return sym;
37 if (sym->ctype.modifiers & (MOD_STATIC | MOD_EXTERN | MOD_TOPLEVEL | MOD_INLINE))
38 return sym;
39 if (!sym->replace) {
40 warning(pos, "unreplaced symbol '%s'", show_ident(sym->ident));
41 return sym;
43 return sym->replace;
46 static struct symbol_list *copy_symbol_list(struct symbol_list *src)
48 struct symbol_list *dst = NULL;
49 struct symbol *sym;
51 FOR_EACH_PTR(src, sym) {
52 struct symbol *newsym = copy_symbol(sym->pos, sym);
53 add_symbol(&dst, newsym);
54 } END_FOR_EACH_PTR(sym);
55 return dst;
58 static struct expression * copy_expression(struct expression *expr)
60 if (!expr)
61 return NULL;
63 switch (expr->type) {
65 * EXPR_SYMBOL is the interesting case, we may need to replace the
66 * symbol to the new copy.
68 case EXPR_SYMBOL: {
69 struct symbol *sym = copy_symbol(expr->pos, expr->symbol);
70 if (sym == expr->symbol)
71 break;
72 expr = dup_expression(expr);
73 expr->symbol = sym;
74 break;
77 /* Atomics, never change, just return the expression directly */
78 case EXPR_VALUE:
79 case EXPR_STRING:
80 case EXPR_FVALUE:
81 break;
83 /* Unops: check if the subexpression is unique */
84 case EXPR_PREOP:
85 case EXPR_POSTOP: {
86 struct expression *unop = copy_expression(expr->unop);
87 if (expr->unop == unop)
88 break;
89 expr = dup_expression(expr);
90 expr->unop = unop;
91 break;
94 case EXPR_SLICE: {
95 struct expression *base = copy_expression(expr->base);
96 expr = dup_expression(expr);
97 expr->base = base;
98 break;
101 /* Binops: copy left/right expressions */
102 case EXPR_BINOP:
103 case EXPR_COMMA:
104 case EXPR_COMPARE:
105 case EXPR_LOGICAL: {
106 struct expression *left = copy_expression(expr->left);
107 struct expression *right = copy_expression(expr->right);
108 if (left == expr->left && right == expr->right)
109 break;
110 expr = dup_expression(expr);
111 expr->left = left;
112 expr->right = right;
113 break;
116 case EXPR_ASSIGNMENT: {
117 struct expression *left = copy_expression(expr->left);
118 struct expression *right = copy_expression(expr->right);
119 if (expr->op == '=' && left == expr->left && right == expr->right)
120 break;
121 expr = dup_expression(expr);
122 expr->left = left;
123 expr->right = right;
124 break;
127 /* Dereference */
128 case EXPR_DEREF: {
129 struct expression *deref = copy_expression(expr->deref);
130 expr = dup_expression(expr);
131 expr->deref = deref;
132 break;
135 /* Cast/sizeof/__alignof__ */
136 case EXPR_CAST:
137 case EXPR_IMPLIED_CAST:
138 case EXPR_SIZEOF:
139 case EXPR_PTRSIZEOF:
140 case EXPR_ALIGNOF: {
141 struct expression *cast = copy_expression(expr->cast_expression);
142 if (cast == expr->cast_expression)
143 break;
144 expr = dup_expression(expr);
145 expr->cast_expression = cast;
146 break;
149 /* Conditional expression */
150 case EXPR_SELECT:
151 case EXPR_CONDITIONAL: {
152 struct expression *cond = copy_expression(expr->conditional);
153 struct expression *true = copy_expression(expr->cond_true);
154 struct expression *false = copy_expression(expr->cond_false);
155 if (cond == expr->conditional && true == expr->cond_true && false == expr->cond_false)
156 break;
157 expr = dup_expression(expr);
158 expr->conditional = cond;
159 expr->cond_true = true;
160 expr->cond_false = false;
161 break;
164 /* Statement expression */
165 case EXPR_STATEMENT: {
166 struct statement *stmt = alloc_statement(expr->pos, STMT_COMPOUND);
167 copy_statement(expr->statement, stmt);
168 expr = dup_expression(expr);
169 expr->statement = stmt;
170 break;
173 /* Call expression */
174 case EXPR_CALL: {
175 struct expression *fn = copy_expression(expr->fn);
176 struct expression_list *list = expr->args;
177 struct expression *arg;
179 expr = dup_expression(expr);
180 expr->fn = fn;
181 expr->args = NULL;
182 FOR_EACH_PTR(list, arg) {
183 add_expression(&expr->args, copy_expression(arg));
184 } END_FOR_EACH_PTR(arg);
185 break;
188 /* Initializer list statement */
189 case EXPR_INITIALIZER: {
190 struct expression_list *list = expr->expr_list;
191 struct expression *entry;
192 expr = dup_expression(expr);
193 expr->expr_list = NULL;
194 FOR_EACH_PTR(list, entry) {
195 add_expression(&expr->expr_list, copy_expression(entry));
196 } END_FOR_EACH_PTR(entry);
197 break;
200 /* Label in inline function - hmm. */
201 case EXPR_LABEL: {
202 struct symbol *label_symbol = copy_symbol(expr->pos, expr->label_symbol);
203 expr = dup_expression(expr);
204 expr->label_symbol = label_symbol;
205 break;
208 case EXPR_INDEX: {
209 struct expression *sub_expr = dup_expression(expr->idx_expression);
210 if (sub_expr == expr->idx_expression)
211 break;
212 expr = dup_expression(expr);
213 expr->idx_expression = sub_expr;
214 break;
217 case EXPR_IDENTIFIER: {
218 struct expression *sub_expr = dup_expression(expr->ident_expression);
219 if (sub_expr == expr->ident_expression)
220 break;
221 expr = dup_expression(expr);
222 expr->ident_expression = sub_expr;
223 break;
226 /* Position in initializer.. */
227 case EXPR_POS: {
228 struct expression *val = copy_expression(expr->init_expr);
229 if (val == expr->init_expr)
230 break;
231 expr = dup_expression(expr);
232 expr->init_expr = val;
233 break;
236 default:
237 warning(expr->pos, "trying to copy expression type %d", expr->type);
239 return expr;
242 void set_replace(struct symbol *old, struct symbol *new)
244 new->replace = old;
245 old->replace = new;
248 void unset_replace(struct symbol *sym)
250 struct symbol *r = sym->replace;
251 if (!r) {
252 warning(sym->pos, "symbol '%s' not replaced?", show_ident(sym->ident));
253 return;
255 r->replace = NULL;
256 sym->replace = NULL;
259 static void unset_replace_list(struct symbol_list *list)
261 struct symbol *sym;
262 FOR_EACH_PTR(list, sym) {
263 unset_replace(sym);
264 } END_FOR_EACH_PTR(sym);
267 static struct statement *copy_one_statement(struct statement *stmt)
269 if (!stmt)
270 return NULL;
271 switch(stmt->type) {
272 case STMT_NONE:
273 break;
274 case STMT_INTERNAL:
275 case STMT_EXPRESSION: {
276 struct expression *expr = copy_expression(stmt->expression);
277 if (expr == stmt->expression)
278 break;
279 stmt = dup_statement(stmt);
280 stmt->expression = expr;
281 break;
283 case STMT_COMPOUND: {
284 struct statement *new = alloc_statement(stmt->pos, STMT_COMPOUND);
285 copy_statement(stmt, new);
286 stmt = new;
287 break;
289 case STMT_IF: {
290 struct expression *cond = stmt->if_conditional;
291 struct statement *true = stmt->if_true;
292 struct statement *false = stmt->if_false;
294 cond = copy_expression(cond);
295 true = copy_one_statement(true);
296 false = copy_one_statement(false);
297 if (stmt->if_conditional == cond &&
298 stmt->if_true == true &&
299 stmt->if_false == false)
300 break;
301 stmt = dup_statement(stmt);
302 stmt->if_conditional = cond;
303 stmt->if_true = true;
304 stmt->if_false = false;
305 break;
307 case STMT_RETURN: {
308 struct expression *retval = copy_expression(stmt->ret_value);
309 struct symbol *sym = copy_symbol(stmt->pos, stmt->ret_target);
311 stmt = dup_statement(stmt);
312 stmt->ret_value = retval;
313 stmt->ret_target = sym;
314 break;
316 case STMT_CASE: {
317 stmt = dup_statement(stmt);
318 stmt->case_label = copy_symbol(stmt->pos, stmt->case_label);
319 stmt->case_expression = copy_expression(stmt->case_expression);
320 stmt->case_to = copy_expression(stmt->case_to);
321 stmt->case_statement = copy_one_statement(stmt->case_statement);
322 break;
324 case STMT_SWITCH: {
325 struct symbol *switch_break = copy_symbol(stmt->pos, stmt->switch_break);
326 struct symbol *switch_case = copy_symbol(stmt->pos, stmt->switch_case);
327 struct expression *expr = copy_expression(stmt->switch_expression);
328 struct statement *switch_stmt = copy_one_statement(stmt->switch_statement);
330 stmt = dup_statement(stmt);
331 switch_case->symbol_list = copy_symbol_list(switch_case->symbol_list);
332 stmt->switch_break = switch_break;
333 stmt->switch_case = switch_case;
334 stmt->switch_expression = expr;
335 stmt->switch_statement = switch_stmt;
336 break;
338 case STMT_ITERATOR: {
339 stmt = dup_statement(stmt);
340 stmt->iterator_break = copy_symbol(stmt->pos, stmt->iterator_break);
341 stmt->iterator_continue = copy_symbol(stmt->pos, stmt->iterator_continue);
342 stmt->iterator_syms = copy_symbol_list(stmt->iterator_syms);
344 stmt->iterator_pre_statement = copy_one_statement(stmt->iterator_pre_statement);
345 stmt->iterator_pre_condition = copy_expression(stmt->iterator_pre_condition);
347 stmt->iterator_statement = copy_one_statement(stmt->iterator_statement);
349 stmt->iterator_post_statement = copy_one_statement(stmt->iterator_post_statement);
350 stmt->iterator_post_condition = copy_expression(stmt->iterator_post_condition);
351 break;
353 case STMT_LABEL: {
354 stmt = dup_statement(stmt);
355 stmt->label_identifier = copy_symbol(stmt->pos, stmt->label_identifier);
356 stmt->label_statement = copy_one_statement(stmt->label_statement);
357 break;
359 case STMT_GOTO: {
360 stmt = dup_statement(stmt);
361 stmt->goto_label = copy_symbol(stmt->pos, stmt->goto_label);
362 stmt->goto_expression = copy_expression(stmt->goto_expression);
363 stmt->target_list = copy_symbol_list(stmt->target_list);
364 break;
366 case STMT_ASM: {
367 /* FIXME! */
368 break;
370 default:
371 warning(stmt->pos, "trying to copy statement type %d", stmt->type);
372 break;
374 return stmt;
378 * Copy a stateemnt tree from 'src' to 'dst', where both
379 * source and destination are of type STMT_COMPOUND.
381 * We do this for the tree-level inliner.
383 * This doesn't do the symbol replacement right: it's not
384 * re-entrant.
386 void copy_statement(struct statement *src, struct statement *dst)
388 struct statement *stmt;
389 struct symbol *sym;
391 FOR_EACH_PTR(src->syms, sym) {
392 struct symbol *newsym = copy_symbol(src->pos, sym);
393 newsym->initializer = copy_expression(sym->initializer);
394 add_symbol(&dst->syms, newsym);
395 } END_FOR_EACH_PTR(sym);
397 FOR_EACH_PTR(src->stmts, stmt) {
398 add_statement(&dst->stmts, copy_one_statement(stmt));
399 } END_FOR_EACH_PTR(stmt);
401 dst->ret = copy_symbol(src->pos, src->ret);
404 static struct symbol *create_copy_symbol(struct symbol *orig)
406 struct symbol *sym = orig;
407 if (orig) {
408 sym = alloc_symbol(orig->pos, orig->type);
409 *sym = *orig;
410 sym->bb_target = NULL;
411 sym->pseudo = NULL;
412 set_replace(orig, sym);
413 orig = sym;
415 return orig;
418 static struct symbol_list *create_symbol_list(struct symbol_list *src)
420 struct symbol_list *dst = NULL;
421 struct symbol *sym;
423 FOR_EACH_PTR(src, sym) {
424 struct symbol *newsym = create_copy_symbol(sym);
425 add_symbol(&dst, newsym);
426 } END_FOR_EACH_PTR(sym);
427 return dst;
430 int inline_function(struct expression *expr, struct symbol *sym)
432 struct symbol_list * fn_symbol_list;
433 struct symbol *fn = sym->ctype.base_type;
434 struct expression_list *arg_list = expr->args;
435 struct statement *stmt = alloc_statement(expr->pos, STMT_COMPOUND);
436 struct symbol_list *name_list;
437 struct symbol *name;
438 struct expression *arg;
440 if (!fn->inline_stmt) {
441 warning(fn->pos, "marked inline, but without a definition");
442 return 0;
444 if (fn->expanding)
445 return 0;
446 fn->expanding = 1;
448 name_list = fn->arguments;
450 expr->type = EXPR_STATEMENT;
451 expr->statement = stmt;
452 expr->ctype = fn->ctype.base_type;
454 fn_symbol_list = create_symbol_list(sym->inline_symbol_list);
456 PREPARE_PTR_LIST(name_list, name);
457 FOR_EACH_PTR(arg_list, arg) {
458 struct symbol *a = alloc_symbol(arg->pos, SYM_NODE);
460 a->ctype.base_type = arg->ctype;
461 if (name) {
462 *a = *name;
463 set_replace(name, a);
464 add_symbol(&fn_symbol_list, a);
466 a->initializer = arg;
467 add_symbol(&stmt->syms, a);
469 NEXT_PTR_LIST(name);
470 } END_FOR_EACH_PTR(arg);
471 FINISH_PTR_LIST(name);
473 copy_statement(fn->inline_stmt, stmt);
475 unset_replace_list(fn_symbol_list);
477 evaluate_statement(stmt);
479 fn->expanding = 0;
480 return 1;
483 void uninline(struct symbol *sym)
485 struct symbol *fn = sym->ctype.base_type;
486 struct symbol_list *arg_list = fn->arguments;
487 struct symbol *p;
489 sym->symbol_list = create_symbol_list(sym->inline_symbol_list);
490 FOR_EACH_PTR(arg_list, p) {
491 p->replace = p;
492 } END_FOR_EACH_PTR(p);
493 fn->stmt = alloc_statement(fn->pos, STMT_COMPOUND);
494 copy_statement(fn->inline_stmt, fn->stmt);
495 unset_replace_list(sym->symbol_list);
496 unset_replace_list(arg_list);