xref: /illumos-gate/usr/src/tools/smatch/src/inline.c (revision 1b58875ad7966cf2c85ee8e92f3da04f0a3b2f7a)
1 /*
2  * Sparse - a semantic source parser.
3  *
4  * Copyright (C) 2003 Transmeta Corp.
5  *               2003-2004 Linus Torvalds
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  */
25 
26 #include <stdlib.h>
27 #include <stdio.h>
28 
29 #include "lib.h"
30 #include "allocate.h"
31 #include "token.h"
32 #include "parse.h"
33 #include "symbol.h"
34 #include "expression.h"
35 
36 static struct expression * dup_expression(struct expression *expr)
37 {
38 	struct expression *dup = alloc_expression(expr->pos, expr->type);
39 	*dup = *expr;
40 	return dup;
41 }
42 
43 static struct statement * dup_statement(struct statement *stmt)
44 {
45 	struct statement *dup = alloc_statement(stmt->pos, stmt->type);
46 	*dup = *stmt;
47 	return dup;
48 }
49 
50 static struct symbol *copy_symbol(struct position pos, struct symbol *sym)
51 {
52 	if (!sym)
53 		return sym;
54 	if (sym->ctype.modifiers & (MOD_STATIC | MOD_EXTERN | MOD_TOPLEVEL | MOD_INLINE))
55 		return sym;
56 	if (!sym->replace) {
57 		warning(pos, "unreplaced symbol '%s'", show_ident(sym->ident));
58 		return sym;
59 	}
60 	return sym->replace;
61 }
62 
63 static struct symbol_list *copy_symbol_list(struct symbol_list *src)
64 {
65 	struct symbol_list *dst = NULL;
66 	struct symbol *sym;
67 
68 	FOR_EACH_PTR(src, sym) {
69 		struct symbol *newsym = copy_symbol(sym->pos, sym);
70 		add_symbol(&dst, newsym);
71 	} END_FOR_EACH_PTR(sym);
72 	return dst;
73 }
74 
75 static struct expression * copy_expression(struct expression *expr)
76 {
77 	if (!expr)
78 		return NULL;
79 
80 	switch (expr->type) {
81 	/*
82 	 * EXPR_SYMBOL is the interesting case, we may need to replace the
83 	 * symbol to the new copy.
84 	 */
85 	case EXPR_SYMBOL: {
86 		struct symbol *sym = copy_symbol(expr->pos, expr->symbol);
87 		if (sym == expr->symbol)
88 			break;
89 		expr = dup_expression(expr);
90 		expr->symbol = sym;
91 		break;
92 	}
93 
94 	/* Atomics, never change, just return the expression directly */
95 	case EXPR_VALUE:
96 	case EXPR_STRING:
97 	case EXPR_FVALUE:
98 	case EXPR_TYPE:
99 		break;
100 
101 	/* Unops: check if the subexpression is unique */
102 	case EXPR_PREOP:
103 	case EXPR_POSTOP: {
104 		struct expression *unop = copy_expression(expr->unop);
105 		if (expr->unop == unop)
106 			break;
107 		expr = dup_expression(expr);
108 		expr->unop = unop;
109 		break;
110 	}
111 
112 	case EXPR_SLICE: {
113 		struct expression *base = copy_expression(expr->base);
114 		expr = dup_expression(expr);
115 		expr->base = base;
116 		break;
117 	}
118 
119 	/* Binops: copy left/right expressions */
120 	case EXPR_BINOP:
121 	case EXPR_COMMA:
122 	case EXPR_COMPARE:
123 	case EXPR_LOGICAL: {
124 		struct expression *left = copy_expression(expr->left);
125 		struct expression *right = copy_expression(expr->right);
126 		if (left == expr->left && right == expr->right)
127 			break;
128 		expr = dup_expression(expr);
129 		expr->left = left;
130 		expr->right = right;
131 		break;
132 	}
133 
134 	case EXPR_ASSIGNMENT: {
135 		struct expression *left = copy_expression(expr->left);
136 		struct expression *right = copy_expression(expr->right);
137 		if (expr->op == '=' && left == expr->left && right == expr->right)
138 			break;
139 		expr = dup_expression(expr);
140 		expr->left = left;
141 		expr->right = right;
142 		break;
143 	}
144 
145 	/* Dereference */
146 	case EXPR_DEREF: {
147 		struct expression *deref = copy_expression(expr->deref);
148 		expr = dup_expression(expr);
149 		expr->deref = deref;
150 		break;
151 	}
152 
153 	/* Cast/sizeof/__alignof__ */
154 	case EXPR_CAST:
155 		if (expr->cast_expression->type == EXPR_INITIALIZER) {
156 			struct expression *cast = expr->cast_expression;
157 			struct symbol *sym = expr->cast_type;
158 			expr = dup_expression(expr);
159 			expr->cast_expression = copy_expression(cast);
160 			expr->cast_type = alloc_symbol(sym->pos, sym->type);
161 			*expr->cast_type = *sym;
162 			break;
163 		}
164 	case EXPR_FORCE_CAST:
165 	case EXPR_IMPLIED_CAST:
166 	case EXPR_SIZEOF:
167 	case EXPR_PTRSIZEOF:
168 	case EXPR_ALIGNOF: {
169 		struct expression *cast = copy_expression(expr->cast_expression);
170 		if (cast == expr->cast_expression)
171 			break;
172 		expr = dup_expression(expr);
173 		expr->cast_expression = cast;
174 		break;
175 	}
176 
177 	/* Conditional expression */
178 	case EXPR_SELECT:
179 	case EXPR_CONDITIONAL: {
180 		struct expression *cond = copy_expression(expr->conditional);
181 		struct expression *true = copy_expression(expr->cond_true);
182 		struct expression *false = copy_expression(expr->cond_false);
183 		if (cond == expr->conditional && true == expr->cond_true && false == expr->cond_false)
184 			break;
185 		expr = dup_expression(expr);
186 		expr->conditional = cond;
187 		expr->cond_true = true;
188 		expr->cond_false = false;
189 		break;
190 	}
191 
192 	/* Statement expression */
193 	case EXPR_STATEMENT: {
194 		struct statement *stmt = alloc_statement(expr->pos, STMT_COMPOUND);
195 		copy_statement(expr->statement, stmt);
196 		expr = dup_expression(expr);
197 		expr->statement = stmt;
198 		break;
199 	}
200 
201 	/* Call expression */
202 	case EXPR_CALL: {
203 		struct expression *fn = copy_expression(expr->fn);
204 		struct expression_list *list = expr->args;
205 		struct expression *arg;
206 
207 		expr = dup_expression(expr);
208 		expr->fn = fn;
209 		expr->args = NULL;
210 		FOR_EACH_PTR(list, arg) {
211 			add_expression(&expr->args, copy_expression(arg));
212 		} END_FOR_EACH_PTR(arg);
213 		break;
214 	}
215 
216 	/* Initializer list statement */
217 	case EXPR_INITIALIZER: {
218 		struct expression_list *list = expr->expr_list;
219 		struct expression *entry;
220 		expr = dup_expression(expr);
221 		expr->expr_list = NULL;
222 		FOR_EACH_PTR(list, entry) {
223 			add_expression(&expr->expr_list, copy_expression(entry));
224 		} END_FOR_EACH_PTR(entry);
225 		break;
226 	}
227 
228 	/* Label in inline function - hmm. */
229 	case EXPR_LABEL: {
230 		struct symbol *label_symbol = copy_symbol(expr->pos, expr->label_symbol);
231 		expr = dup_expression(expr);
232 		expr->label_symbol = label_symbol;
233 		break;
234 	}
235 
236 	case EXPR_INDEX: {
237 		struct expression *sub_expr = copy_expression(expr->idx_expression);
238 		expr = dup_expression(expr);
239 		expr->idx_expression = sub_expr;
240 		break;
241 	}
242 
243 	case EXPR_IDENTIFIER: {
244 		struct expression *sub_expr = copy_expression(expr->ident_expression);
245 		expr = dup_expression(expr);
246 		expr->ident_expression = sub_expr;
247 		break;
248 	}
249 
250 	/* Position in initializer.. */
251 	case EXPR_POS: {
252 		struct expression *val = copy_expression(expr->init_expr);
253 		expr = dup_expression(expr);
254 		expr->init_expr = val;
255 		break;
256 	}
257 	case EXPR_OFFSETOF: {
258 		struct expression *val = copy_expression(expr->down);
259 		if (expr->op == '.') {
260 			if (expr->down != val) {
261 				expr = dup_expression(expr);
262 				expr->down = val;
263 			}
264 		} else {
265 			struct expression *idx = copy_expression(expr->index);
266 			if (expr->down != val || expr->index != idx) {
267 				expr = dup_expression(expr);
268 				expr->down = val;
269 				expr->index = idx;
270 			}
271 		}
272 		break;
273 	}
274 	default:
275 		warning(expr->pos, "trying to copy expression type %d", expr->type);
276 	}
277 	return expr;
278 }
279 
280 static struct expression_list *copy_asm_constraints(struct expression_list *in)
281 {
282 	struct expression_list *out = NULL;
283 	struct expression *expr;
284 	int state = 0;
285 
286 	FOR_EACH_PTR(in, expr) {
287 		switch (state) {
288 		case 0: /* identifier */
289 		case 1: /* constraint */
290 			state++;
291 			add_expression(&out, expr);
292 			continue;
293 		case 2: /* expression */
294 			state = 0;
295 			add_expression(&out, copy_expression(expr));
296 			continue;
297 		}
298 	} END_FOR_EACH_PTR(expr);
299 	return out;
300 }
301 
302 static void set_replace(struct symbol *old, struct symbol *new)
303 {
304 	new->replace = old;
305 	old->replace = new;
306 }
307 
308 static void unset_replace(struct symbol *sym)
309 {
310 	struct symbol *r = sym->replace;
311 	if (!r) {
312 		warning(sym->pos, "symbol '%s' not replaced?", show_ident(sym->ident));
313 		return;
314 	}
315 	r->replace = NULL;
316 	sym->replace = NULL;
317 }
318 
319 static void unset_replace_list(struct symbol_list *list)
320 {
321 	struct symbol *sym;
322 	FOR_EACH_PTR(list, sym) {
323 		unset_replace(sym);
324 	} END_FOR_EACH_PTR(sym);
325 }
326 
327 static struct statement *copy_one_statement(struct statement *stmt)
328 {
329 	if (!stmt)
330 		return NULL;
331 	switch(stmt->type) {
332 	case STMT_NONE:
333 		break;
334 	case STMT_DECLARATION: {
335 		struct symbol *sym;
336 		struct statement *newstmt = dup_statement(stmt);
337 		newstmt->declaration = NULL;
338 		FOR_EACH_PTR(stmt->declaration, sym) {
339 			struct symbol *newsym = copy_symbol(stmt->pos, sym);
340 			if (newsym != sym)
341 				newsym->initializer = copy_expression(sym->initializer);
342 			add_symbol(&newstmt->declaration, newsym);
343 		} END_FOR_EACH_PTR(sym);
344 		stmt = newstmt;
345 		break;
346 	}
347 	case STMT_CONTEXT:
348 	case STMT_EXPRESSION: {
349 		struct expression *expr = copy_expression(stmt->expression);
350 		if (expr == stmt->expression)
351 			break;
352 		stmt = dup_statement(stmt);
353 		stmt->expression = expr;
354 		break;
355 	}
356 	case STMT_RANGE: {
357 		struct expression *expr = copy_expression(stmt->range_expression);
358 		if (expr == stmt->expression)
359 			break;
360 		stmt = dup_statement(stmt);
361 		stmt->range_expression = expr;
362 		break;
363 	}
364 	case STMT_COMPOUND: {
365 		struct statement *new = alloc_statement(stmt->pos, STMT_COMPOUND);
366 		copy_statement(stmt, new);
367 		stmt = new;
368 		break;
369 	}
370 	case STMT_IF: {
371 		struct expression *cond = stmt->if_conditional;
372 		struct statement *true = stmt->if_true;
373 		struct statement *false = stmt->if_false;
374 
375 		cond = copy_expression(cond);
376 		true = copy_one_statement(true);
377 		false = copy_one_statement(false);
378 		if (stmt->if_conditional == cond &&
379 		    stmt->if_true == true &&
380 		    stmt->if_false == false)
381 			break;
382 		stmt = dup_statement(stmt);
383 		stmt->if_conditional = cond;
384 		stmt->if_true = true;
385 		stmt->if_false = false;
386 		break;
387 	}
388 	case STMT_RETURN: {
389 		struct expression *retval = copy_expression(stmt->ret_value);
390 		struct symbol *sym = copy_symbol(stmt->pos, stmt->ret_target);
391 
392 		stmt = dup_statement(stmt);
393 		stmt->ret_value = retval;
394 		stmt->ret_target = sym;
395 		break;
396 	}
397 	case STMT_CASE: {
398 		stmt = dup_statement(stmt);
399 		stmt->case_label = copy_symbol(stmt->pos, stmt->case_label);
400 		stmt->case_label->stmt = stmt;
401 		stmt->case_expression = copy_expression(stmt->case_expression);
402 		stmt->case_to = copy_expression(stmt->case_to);
403 		stmt->case_statement = copy_one_statement(stmt->case_statement);
404 		break;
405 	}
406 	case STMT_SWITCH: {
407 		struct symbol *switch_break = copy_symbol(stmt->pos, stmt->switch_break);
408 		struct symbol *switch_case = copy_symbol(stmt->pos, stmt->switch_case);
409 		struct expression *expr = copy_expression(stmt->switch_expression);
410 		struct statement *switch_stmt = copy_one_statement(stmt->switch_statement);
411 
412 		stmt = dup_statement(stmt);
413 		switch_case->symbol_list = copy_symbol_list(switch_case->symbol_list);
414 		stmt->switch_break = switch_break;
415 		stmt->switch_case = switch_case;
416 		stmt->switch_expression = expr;
417 		stmt->switch_statement = switch_stmt;
418 		break;
419 	}
420 	case STMT_ITERATOR: {
421 		stmt = dup_statement(stmt);
422 		stmt->iterator_break = copy_symbol(stmt->pos, stmt->iterator_break);
423 		stmt->iterator_continue = copy_symbol(stmt->pos, stmt->iterator_continue);
424 		stmt->iterator_syms = copy_symbol_list(stmt->iterator_syms);
425 
426 		stmt->iterator_pre_statement = copy_one_statement(stmt->iterator_pre_statement);
427 		stmt->iterator_pre_condition = copy_expression(stmt->iterator_pre_condition);
428 
429 		stmt->iterator_statement = copy_one_statement(stmt->iterator_statement);
430 
431 		stmt->iterator_post_statement = copy_one_statement(stmt->iterator_post_statement);
432 		stmt->iterator_post_condition = copy_expression(stmt->iterator_post_condition);
433 		break;
434 	}
435 	case STMT_LABEL: {
436 		stmt = dup_statement(stmt);
437 		stmt->label_identifier = copy_symbol(stmt->pos, stmt->label_identifier);
438 		stmt->label_statement = copy_one_statement(stmt->label_statement);
439 		break;
440 	}
441 	case STMT_GOTO: {
442 		stmt = dup_statement(stmt);
443 		stmt->goto_label = copy_symbol(stmt->pos, stmt->goto_label);
444 		stmt->goto_expression = copy_expression(stmt->goto_expression);
445 		stmt->target_list = copy_symbol_list(stmt->target_list);
446 		break;
447 	}
448 	case STMT_ASM: {
449 		stmt = dup_statement(stmt);
450 		stmt->asm_inputs = copy_asm_constraints(stmt->asm_inputs);
451 		stmt->asm_outputs = copy_asm_constraints(stmt->asm_outputs);
452 		/* no need to dup "clobbers", since they are all constant strings */
453 		break;
454 	}
455 	default:
456 		warning(stmt->pos, "trying to copy statement type %d", stmt->type);
457 		break;
458 	}
459 	return stmt;
460 }
461 
462 /*
463  * Copy a statement tree from 'src' to 'dst', where both
464  * source and destination are of type STMT_COMPOUND.
465  *
466  * We do this for the tree-level inliner.
467  *
468  * This doesn't do the symbol replacement right: it's not
469  * re-entrant.
470  */
471 void copy_statement(struct statement *src, struct statement *dst)
472 {
473 	struct statement *stmt;
474 
475 	FOR_EACH_PTR(src->stmts, stmt) {
476 		add_statement(&dst->stmts, copy_one_statement(stmt));
477 	} END_FOR_EACH_PTR(stmt);
478 	dst->args = copy_one_statement(src->args);
479 	dst->ret = copy_symbol(src->pos, src->ret);
480 	dst->inline_fn = src->inline_fn;
481 }
482 
483 static struct symbol *create_copy_symbol(struct symbol *orig)
484 {
485 	struct symbol *sym = orig;
486 	if (orig) {
487 		sym = alloc_symbol(orig->pos, orig->type);
488 		*sym = *orig;
489 		sym->bb_target = NULL;
490 		sym->pseudo = NULL;
491 		set_replace(orig, sym);
492 		orig = sym;
493 	}
494 	return orig;
495 }
496 
497 static struct symbol_list *create_symbol_list(struct symbol_list *src)
498 {
499 	struct symbol_list *dst = NULL;
500 	struct symbol *sym;
501 
502 	FOR_EACH_PTR(src, sym) {
503 		struct symbol *newsym = create_copy_symbol(sym);
504 		add_symbol(&dst, newsym);
505 	} END_FOR_EACH_PTR(sym);
506 	return dst;
507 }
508 
509 int inline_function(struct expression *expr, struct symbol *sym)
510 {
511 	struct symbol_list * fn_symbol_list;
512 	struct symbol *fn = sym->ctype.base_type;
513 	struct expression_list *arg_list = expr->args;
514 	struct statement *stmt = alloc_statement(expr->pos, STMT_COMPOUND);
515 	struct symbol_list *name_list, *arg_decl;
516 	struct symbol *name;
517 	struct expression *arg;
518 
519 	if (!fn->inline_stmt) {
520 		sparse_error(fn->pos, "marked inline, but without a definition");
521 		return 0;
522 	}
523 	if (fn->expanding)
524 		return 0;
525 
526 	fn->expanding = 1;
527 
528 	name_list = fn->arguments;
529 
530 	expr->type = EXPR_STATEMENT;
531 	expr->statement = stmt;
532 	expr->ctype = fn->ctype.base_type;
533 
534 	fn_symbol_list = create_symbol_list(sym->inline_symbol_list);
535 
536 	arg_decl = NULL;
537 	PREPARE_PTR_LIST(name_list, name);
538 	FOR_EACH_PTR(arg_list, arg) {
539 		struct symbol *a = alloc_symbol(arg->pos, SYM_NODE);
540 
541 		a->ctype.base_type = arg->ctype;
542 		if (name) {
543 			*a = *name;
544 			set_replace(name, a);
545 			add_symbol(&fn_symbol_list, a);
546 		}
547 		a->initializer = arg;
548 		add_symbol(&arg_decl, a);
549 
550 		NEXT_PTR_LIST(name);
551 	} END_FOR_EACH_PTR(arg);
552 	FINISH_PTR_LIST(name);
553 
554 	copy_statement(fn->inline_stmt, stmt);
555 
556 	if (arg_decl) {
557 		struct statement *decl = alloc_statement(expr->pos, STMT_DECLARATION);
558 		decl->declaration = arg_decl;
559 		stmt->args = decl;
560 	}
561 	stmt->inline_fn = sym;
562 
563 	unset_replace_list(fn_symbol_list);
564 
565 	evaluate_statement(stmt);
566 
567 	fn->expanding = 0;
568 	return 1;
569 }
570 
571 void uninline(struct symbol *sym)
572 {
573 	struct symbol *fn = sym->ctype.base_type;
574 	struct symbol_list *arg_list = fn->arguments;
575 	struct symbol *p;
576 
577 	sym->symbol_list = create_symbol_list(sym->inline_symbol_list);
578 	FOR_EACH_PTR(arg_list, p) {
579 		p->replace = p;
580 	} END_FOR_EACH_PTR(p);
581 	fn->stmt = alloc_statement(fn->pos, STMT_COMPOUND);
582 	copy_statement(fn->inline_stmt, fn->stmt);
583 	unset_replace_list(sym->symbol_list);
584 	unset_replace_list(arg_list);
585 }
586