handle if (*ptr == 5)
[smatch.git] / inline.c
blob09d176a7d23ad3c9441d5d6c00df699f9632c64d
1 /*
2 * Sparse - a semantic source parser.
4 * Copyright (C) 2003 Transmeta Corp.
5 * 2003-2004 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 "allocate.h"
15 #include "token.h"
16 #include "parse.h"
17 #include "symbol.h"
18 #include "expression.h"
20 static struct expression * dup_expression(struct expression *expr)
22 struct expression *dup = alloc_expression(expr->pos, expr->type);
23 *dup = *expr;
24 return dup;
27 static struct statement * dup_statement(struct statement *stmt)
29 struct statement *dup = alloc_statement(stmt->pos, stmt->type);
30 *dup = *stmt;
31 return dup;
34 static struct symbol *copy_symbol(struct position pos, struct symbol *sym)
36 if (!sym)
37 return sym;
38 if (sym->ctype.modifiers & (MOD_STATIC | MOD_EXTERN | MOD_TOPLEVEL | MOD_INLINE))
39 return sym;
40 if (!sym->replace) {
41 warning(pos, "unreplaced symbol '%s'", show_ident(sym->ident));
42 return sym;
44 return sym->replace;
47 static struct symbol_list *copy_symbol_list(struct symbol_list *src)
49 struct symbol_list *dst = NULL;
50 struct symbol *sym;
52 FOR_EACH_PTR(src, sym) {
53 struct symbol *newsym = copy_symbol(sym->pos, sym);
54 add_symbol(&dst, newsym);
55 } END_FOR_EACH_PTR(sym);
56 return dst;
59 static struct expression * copy_expression(struct expression *expr)
61 if (!expr)
62 return NULL;
64 switch (expr->type) {
66 * EXPR_SYMBOL is the interesting case, we may need to replace the
67 * symbol to the new copy.
69 case EXPR_SYMBOL: {
70 struct symbol *sym = copy_symbol(expr->pos, expr->symbol);
71 if (sym == expr->symbol)
72 break;
73 expr = dup_expression(expr);
74 expr->symbol = sym;
75 break;
78 /* Atomics, never change, just return the expression directly */
79 case EXPR_VALUE:
80 case EXPR_STRING:
81 case EXPR_FVALUE:
82 case EXPR_TYPE:
83 break;
85 /* Unops: check if the subexpression is unique */
86 case EXPR_PREOP:
87 case EXPR_POSTOP: {
88 struct expression *unop = copy_expression(expr->unop);
89 if (expr->unop == unop)
90 break;
91 expr = dup_expression(expr);
92 expr->unop = unop;
93 break;
96 case EXPR_SLICE: {
97 struct expression *base = copy_expression(expr->base);
98 expr = dup_expression(expr);
99 expr->base = base;
100 break;
103 /* Binops: copy left/right expressions */
104 case EXPR_BINOP:
105 case EXPR_COMMA:
106 case EXPR_COMPARE:
107 case EXPR_LOGICAL: {
108 struct expression *left = copy_expression(expr->left);
109 struct expression *right = copy_expression(expr->right);
110 if (left == expr->left && right == expr->right)
111 break;
112 expr = dup_expression(expr);
113 expr->left = left;
114 expr->right = right;
115 break;
118 case EXPR_ASSIGNMENT: {
119 struct expression *left = copy_expression(expr->left);
120 struct expression *right = copy_expression(expr->right);
121 if (expr->op == '=' && left == expr->left && right == expr->right)
122 break;
123 expr = dup_expression(expr);
124 expr->left = left;
125 expr->right = right;
126 break;
129 /* Dereference */
130 case EXPR_DEREF: {
131 struct expression *deref = copy_expression(expr->deref);
132 expr = dup_expression(expr);
133 expr->deref = deref;
134 break;
137 /* Cast/sizeof/__alignof__ */
138 case EXPR_CAST:
139 if (expr->cast_expression->type == EXPR_INITIALIZER) {
140 struct expression *cast = expr->cast_expression;
141 struct symbol *sym = expr->cast_type;
142 expr = dup_expression(expr);
143 expr->cast_expression = copy_expression(cast);
144 expr->cast_type = alloc_symbol(sym->pos, sym->type);
145 *expr->cast_type = *sym;
146 break;
148 case EXPR_FORCE_CAST:
149 case EXPR_IMPLIED_CAST:
150 case EXPR_SIZEOF:
151 case EXPR_PTRSIZEOF:
152 case EXPR_ALIGNOF: {
153 struct expression *cast = copy_expression(expr->cast_expression);
154 if (cast == expr->cast_expression)
155 break;
156 expr = dup_expression(expr);
157 expr->cast_expression = cast;
158 break;
161 /* Conditional expression */
162 case EXPR_SELECT:
163 case EXPR_CONDITIONAL: {
164 struct expression *cond = copy_expression(expr->conditional);
165 struct expression *true = copy_expression(expr->cond_true);
166 struct expression *false = copy_expression(expr->cond_false);
167 if (cond == expr->conditional && true == expr->cond_true && false == expr->cond_false)
168 break;
169 expr = dup_expression(expr);
170 expr->conditional = cond;
171 expr->cond_true = true;
172 expr->cond_false = false;
173 break;
176 /* Statement expression */
177 case EXPR_STATEMENT: {
178 struct statement *stmt = alloc_statement(expr->pos, STMT_COMPOUND);
179 copy_statement(expr->statement, stmt);
180 expr = dup_expression(expr);
181 expr->statement = stmt;
182 break;
185 /* Call expression */
186 case EXPR_CALL: {
187 struct expression *fn = copy_expression(expr->fn);
188 struct expression_list *list = expr->args;
189 struct expression *arg;
191 expr = dup_expression(expr);
192 expr->fn = fn;
193 expr->args = NULL;
194 FOR_EACH_PTR(list, arg) {
195 add_expression(&expr->args, copy_expression(arg));
196 } END_FOR_EACH_PTR(arg);
197 break;
200 /* Initializer list statement */
201 case EXPR_INITIALIZER: {
202 struct expression_list *list = expr->expr_list;
203 struct expression *entry;
204 expr = dup_expression(expr);
205 expr->expr_list = NULL;
206 FOR_EACH_PTR(list, entry) {
207 add_expression(&expr->expr_list, copy_expression(entry));
208 } END_FOR_EACH_PTR(entry);
209 break;
212 /* Label in inline function - hmm. */
213 case EXPR_LABEL: {
214 struct symbol *label_symbol = copy_symbol(expr->pos, expr->label_symbol);
215 expr = dup_expression(expr);
216 expr->label_symbol = label_symbol;
217 break;
220 case EXPR_INDEX: {
221 struct expression *sub_expr = copy_expression(expr->idx_expression);
222 expr = dup_expression(expr);
223 expr->idx_expression = sub_expr;
224 break;
227 case EXPR_IDENTIFIER: {
228 struct expression *sub_expr = copy_expression(expr->ident_expression);
229 expr = dup_expression(expr);
230 expr->ident_expression = sub_expr;
231 break;
234 /* Position in initializer.. */
235 case EXPR_POS: {
236 struct expression *val = copy_expression(expr->init_expr);
237 expr = dup_expression(expr);
238 expr->init_expr = val;
239 break;
241 case EXPR_OFFSETOF: {
242 struct expression *val = copy_expression(expr->down);
243 if (expr->op == '.') {
244 if (expr->down != val) {
245 expr = dup_expression(expr);
246 expr->down = val;
248 } else {
249 struct expression *idx = copy_expression(expr->index);
250 if (expr->down != val || expr->index != idx) {
251 expr = dup_expression(expr);
252 expr->down = val;
253 expr->index = idx;
256 break;
258 default:
259 warning(expr->pos, "trying to copy expression type %d", expr->type);
261 return expr;
264 static struct expression_list *copy_asm_constraints(struct expression_list *in)
266 struct expression_list *out = NULL;
267 struct expression *expr;
268 int state = 0;
270 FOR_EACH_PTR(in, expr) {
271 switch (state) {
272 case 0: /* identifier */
273 case 1: /* constraint */
274 state++;
275 add_expression(&out, expr);
276 continue;
277 case 2: /* expression */
278 state = 0;
279 add_expression(&out, copy_expression(expr));
280 continue;
282 } END_FOR_EACH_PTR(expr);
283 return out;
286 static void set_replace(struct symbol *old, struct symbol *new)
288 new->replace = old;
289 old->replace = new;
292 static void unset_replace(struct symbol *sym)
294 struct symbol *r = sym->replace;
295 if (!r) {
296 warning(sym->pos, "symbol '%s' not replaced?", show_ident(sym->ident));
297 return;
299 r->replace = NULL;
300 sym->replace = NULL;
303 static void unset_replace_list(struct symbol_list *list)
305 struct symbol *sym;
306 FOR_EACH_PTR(list, sym) {
307 unset_replace(sym);
308 } END_FOR_EACH_PTR(sym);
311 static struct statement *copy_one_statement(struct statement *stmt)
313 if (!stmt)
314 return NULL;
315 switch(stmt->type) {
316 case STMT_NONE:
317 break;
318 case STMT_DECLARATION: {
319 struct symbol *sym;
320 struct statement *newstmt = dup_statement(stmt);
321 newstmt->declaration = NULL;
322 FOR_EACH_PTR(stmt->declaration, sym) {
323 struct symbol *newsym = copy_symbol(stmt->pos, sym);
324 if (newsym != sym)
325 newsym->initializer = copy_expression(sym->initializer);
326 add_symbol(&newstmt->declaration, newsym);
327 } END_FOR_EACH_PTR(sym);
328 stmt = newstmt;
329 break;
331 case STMT_CONTEXT:
332 case STMT_EXPRESSION: {
333 struct expression *expr = copy_expression(stmt->expression);
334 struct statement *newstmt;
335 if (expr == stmt->expression)
336 break;
337 newstmt = dup_statement(stmt);
338 newstmt->expression = expr;
339 if (stmt->required) {
340 expr = copy_expression(stmt->required);
341 if (expr == stmt->required)
342 break;
343 newstmt->required = expr;
345 stmt = newstmt;
346 break;
348 case STMT_RANGE: {
349 struct expression *expr = copy_expression(stmt->range_expression);
350 if (expr == stmt->expression)
351 break;
352 stmt = dup_statement(stmt);
353 stmt->range_expression = expr;
354 break;
356 case STMT_COMPOUND: {
357 struct statement *new = alloc_statement(stmt->pos, STMT_COMPOUND);
358 copy_statement(stmt, new);
359 stmt = new;
360 break;
362 case STMT_IF: {
363 struct expression *cond = stmt->if_conditional;
364 struct statement *true = stmt->if_true;
365 struct statement *false = stmt->if_false;
367 cond = copy_expression(cond);
368 true = copy_one_statement(true);
369 false = copy_one_statement(false);
370 if (stmt->if_conditional == cond &&
371 stmt->if_true == true &&
372 stmt->if_false == false)
373 break;
374 stmt = dup_statement(stmt);
375 stmt->if_conditional = cond;
376 stmt->if_true = true;
377 stmt->if_false = false;
378 break;
380 case STMT_RETURN: {
381 struct expression *retval = copy_expression(stmt->ret_value);
382 struct symbol *sym = copy_symbol(stmt->pos, stmt->ret_target);
384 stmt = dup_statement(stmt);
385 stmt->ret_value = retval;
386 stmt->ret_target = sym;
387 break;
389 case STMT_CASE: {
390 stmt = dup_statement(stmt);
391 stmt->case_label = copy_symbol(stmt->pos, stmt->case_label);
392 stmt->case_expression = copy_expression(stmt->case_expression);
393 stmt->case_to = copy_expression(stmt->case_to);
394 stmt->case_statement = copy_one_statement(stmt->case_statement);
395 break;
397 case STMT_SWITCH: {
398 struct symbol *switch_break = copy_symbol(stmt->pos, stmt->switch_break);
399 struct symbol *switch_case = copy_symbol(stmt->pos, stmt->switch_case);
400 struct expression *expr = copy_expression(stmt->switch_expression);
401 struct statement *switch_stmt = copy_one_statement(stmt->switch_statement);
403 stmt = dup_statement(stmt);
404 switch_case->symbol_list = copy_symbol_list(switch_case->symbol_list);
405 stmt->switch_break = switch_break;
406 stmt->switch_case = switch_case;
407 stmt->switch_expression = expr;
408 stmt->switch_statement = switch_stmt;
409 break;
411 case STMT_ITERATOR: {
412 stmt = dup_statement(stmt);
413 stmt->iterator_break = copy_symbol(stmt->pos, stmt->iterator_break);
414 stmt->iterator_continue = copy_symbol(stmt->pos, stmt->iterator_continue);
415 stmt->iterator_syms = copy_symbol_list(stmt->iterator_syms);
417 stmt->iterator_pre_statement = copy_one_statement(stmt->iterator_pre_statement);
418 stmt->iterator_pre_condition = copy_expression(stmt->iterator_pre_condition);
420 stmt->iterator_statement = copy_one_statement(stmt->iterator_statement);
422 stmt->iterator_post_statement = copy_one_statement(stmt->iterator_post_statement);
423 stmt->iterator_post_condition = copy_expression(stmt->iterator_post_condition);
424 break;
426 case STMT_LABEL: {
427 stmt = dup_statement(stmt);
428 stmt->label_identifier = copy_symbol(stmt->pos, stmt->label_identifier);
429 stmt->label_statement = copy_one_statement(stmt->label_statement);
430 break;
432 case STMT_GOTO: {
433 stmt = dup_statement(stmt);
434 stmt->goto_label = copy_symbol(stmt->pos, stmt->goto_label);
435 stmt->goto_expression = copy_expression(stmt->goto_expression);
436 stmt->target_list = copy_symbol_list(stmt->target_list);
437 break;
439 case STMT_ASM: {
440 stmt = dup_statement(stmt);
441 stmt->asm_inputs = copy_asm_constraints(stmt->asm_inputs);
442 stmt->asm_outputs = copy_asm_constraints(stmt->asm_outputs);
443 /* no need to dup "clobbers", since they are all constant strings */
444 break;
446 default:
447 warning(stmt->pos, "trying to copy statement type %d", stmt->type);
448 break;
450 return stmt;
454 * Copy a statement tree from 'src' to 'dst', where both
455 * source and destination are of type STMT_COMPOUND.
457 * We do this for the tree-level inliner.
459 * This doesn't do the symbol replacement right: it's not
460 * re-entrant.
462 void copy_statement(struct statement *src, struct statement *dst)
464 struct statement *stmt;
466 FOR_EACH_PTR(src->stmts, stmt) {
467 add_statement(&dst->stmts, copy_one_statement(stmt));
468 } END_FOR_EACH_PTR(stmt);
469 dst->args = copy_one_statement(src->args);
470 dst->ret = copy_symbol(src->pos, src->ret);
471 dst->inline_fn = src->inline_fn;
474 static struct symbol *create_copy_symbol(struct symbol *orig)
476 struct symbol *sym = orig;
477 if (orig) {
478 sym = alloc_symbol(orig->pos, orig->type);
479 *sym = *orig;
480 sym->bb_target = NULL;
481 sym->pseudo = NULL;
482 set_replace(orig, sym);
483 orig = sym;
485 return orig;
488 static struct symbol_list *create_symbol_list(struct symbol_list *src)
490 struct symbol_list *dst = NULL;
491 struct symbol *sym;
493 FOR_EACH_PTR(src, sym) {
494 struct symbol *newsym = create_copy_symbol(sym);
495 add_symbol(&dst, newsym);
496 } END_FOR_EACH_PTR(sym);
497 return dst;
500 int inline_function(struct expression *expr, struct symbol *sym)
502 struct symbol_list * fn_symbol_list;
503 struct symbol *fn = sym->ctype.base_type;
504 struct expression_list *arg_list = expr->args;
505 struct statement *stmt = alloc_statement(expr->pos, STMT_COMPOUND);
506 struct symbol_list *name_list, *arg_decl;
507 struct symbol *name;
508 struct expression *arg;
510 if (!fn->inline_stmt) {
511 sparse_error(fn->pos, "marked inline, but without a definition");
512 return 0;
514 if (fn->expanding)
515 return 0;
517 fn->expanding = 1;
519 name_list = fn->arguments;
521 expr->type = EXPR_STATEMENT;
522 expr->statement = stmt;
523 expr->ctype = fn->ctype.base_type;
525 fn_symbol_list = create_symbol_list(sym->inline_symbol_list);
527 arg_decl = NULL;
528 PREPARE_PTR_LIST(name_list, name);
529 FOR_EACH_PTR(arg_list, arg) {
530 struct symbol *a = alloc_symbol(arg->pos, SYM_NODE);
532 a->ctype.base_type = arg->ctype;
533 if (name) {
534 *a = *name;
535 set_replace(name, a);
536 add_symbol(&fn_symbol_list, a);
538 a->initializer = arg;
539 add_symbol(&arg_decl, a);
541 NEXT_PTR_LIST(name);
542 } END_FOR_EACH_PTR(arg);
543 FINISH_PTR_LIST(name);
545 copy_statement(fn->inline_stmt, stmt);
547 if (arg_decl) {
548 struct statement *decl = alloc_statement(expr->pos, STMT_DECLARATION);
549 decl->declaration = arg_decl;
550 stmt->args = decl;
552 stmt->inline_fn = sym;
554 unset_replace_list(fn_symbol_list);
556 evaluate_statement(stmt);
558 fn->expanding = 0;
559 return 1;
562 void uninline(struct symbol *sym)
564 struct symbol *fn = sym->ctype.base_type;
565 struct symbol_list *arg_list = fn->arguments;
566 struct symbol *p;
568 sym->symbol_list = create_symbol_list(sym->inline_symbol_list);
569 FOR_EACH_PTR(arg_list, p) {
570 p->replace = p;
571 } END_FOR_EACH_PTR(p);
572 fn->stmt = alloc_statement(fn->pos, STMT_COMPOUND);
573 copy_statement(fn->inline_stmt, fn->stmt);
574 unset_replace_list(sym->symbol_list);
575 unset_replace_list(arg_list);