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