/* * sparse/show-parse.c * * Copyright (C) 2003 Transmeta Corp. * 2003-2004 Linus Torvalds * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * Print out results of parsing for debugging and testing. */ #include #include #include #include #include #include #include #include "lib.h" #include "allocate.h" #include "token.h" #include "parse.h" #include "symbol.h" #include "scope.h" #include "expression.h" #include "target.h" static int show_symbol_expr(struct symbol *sym); static int show_string_expr(struct expression *expr); static void do_debug_symbol(struct symbol *sym, int indent) { static const char indent_string[] = " "; static const char *typestr[] = { [SYM_UNINITIALIZED] = "none", [SYM_PREPROCESSOR] = "cpp.", [SYM_BASETYPE] = "base", [SYM_NODE] = "node", [SYM_PTR] = "ptr.", [SYM_FN] = "fn..", [SYM_ARRAY] = "arry", [SYM_STRUCT] = "strt", [SYM_UNION] = "unin", [SYM_ENUM] = "enum", [SYM_TYPEDEF] = "tdef", [SYM_TYPEOF] = "tpof", [SYM_MEMBER] = "memb", [SYM_BITFIELD] = "bitf", [SYM_LABEL] = "labl", [SYM_RESTRICT] = "rstr", [SYM_FOULED] = "foul", [SYM_BAD] = "bad.", }; struct context *context; int i; if (!sym) return; fprintf(stderr, "%.*s%s%3d:%lu %s %s (as: %s) %p (%s:%d:%d) %s\n", indent, indent_string, typestr[sym->type], sym->bit_size, sym->ctype.alignment, modifier_string(sym->ctype.modifiers), show_ident(sym->ident), show_as(sym->ctype.as), sym, stream_name(sym->pos.stream), sym->pos.line, sym->pos.pos, builtin_typename(sym) ?: ""); i = 0; FOR_EACH_PTR(sym->ctype.contexts, context) { /* FIXME: should print context expression */ fprintf(stderr, "< context%d: in=%d, out=%d\n", i, context->in, context->out); fprintf(stderr, " end context%d >\n", i); i++; } END_FOR_EACH_PTR(context); if (sym->type == SYM_FN) { struct symbol *arg; i = 0; FOR_EACH_PTR(sym->arguments, arg) { fprintf(stderr, "< arg%d:\n", i); do_debug_symbol(arg, 0); fprintf(stderr, " end arg%d >\n", i); i++; } END_FOR_EACH_PTR(arg); } do_debug_symbol(sym->ctype.base_type, indent+2); } void debug_symbol(struct symbol *sym) { do_debug_symbol(sym, 0); } /* * Symbol type printout. The type system is by far the most * complicated part of C - everything else is trivial. */ const char *modifier_string(unsigned long mod) { static char buffer[100]; int len = 0; int i; struct mod_name { unsigned long mod; const char *name; } *m; static struct mod_name mod_names[] = { {MOD_AUTO, "auto"}, {MOD_REGISTER, "register"}, {MOD_STATIC, "static"}, {MOD_EXTERN, "extern"}, {MOD_CONST, "const"}, {MOD_VOLATILE, "volatile"}, {MOD_RESTRICT, "restrict"}, {MOD_ATOMIC, "[atomic]"}, {MOD_SIGNED, "[signed]"}, {MOD_UNSIGNED, "[unsigned]"}, {MOD_CHAR, "[char]"}, {MOD_SHORT, "[short]"}, {MOD_LONG, "[long]"}, {MOD_LONGLONG, "[long long]"}, {MOD_LONGLONGLONG, "[long long long]"}, {MOD_TLS, "[tls]"}, {MOD_INLINE, "inline"}, {MOD_ADDRESSABLE, "[addressable]"}, {MOD_NOCAST, "[nocast]"}, {MOD_NODEREF, "[noderef]"}, {MOD_TOPLEVEL, "[toplevel]"}, {MOD_ASSIGNED, "[assigned]"}, {MOD_TYPE, "[type]"}, {MOD_SAFE, "[safe]"}, {MOD_USERTYPE, "[usertype]"}, {MOD_NORETURN, "[noreturn]"}, {MOD_EXPLICITLY_SIGNED, "[explicitly-signed]"}, {MOD_BITWISE, "[bitwise]"}, {MOD_PURE, "[pure]"}, }; for (i = 0; i < ARRAY_SIZE(mod_names); i++) { m = mod_names + i; if (mod & m->mod) { char c; const char *name = m->name; while ((c = *name++) != '\0' && len + 2 < sizeof buffer) buffer[len++] = c; buffer[len++] = ' '; } } buffer[len] = 0; return buffer; } static void show_struct_member(struct symbol *sym) { printf("\t%s:%d:%ld at offset %ld.%d", show_ident(sym->ident), sym->bit_size, sym->ctype.alignment, sym->offset, sym->bit_offset); printf("\n"); } void show_symbol_list(struct symbol_list *list, const char *sep) { struct symbol *sym; const char *prepend = ""; FOR_EACH_PTR(list, sym) { puts(prepend); prepend = ", "; show_symbol(sym); } END_FOR_EACH_PTR(sym); } const char *show_as(struct ident *as) { if (!as) return ""; return show_ident(as); } struct type_name { char *start; char *end; }; static void FORMAT_ATTR(2) prepend(struct type_name *name, const char *fmt, ...) { static char buffer[512]; int n; va_list args; va_start(args, fmt); n = vsprintf(buffer, fmt, args); va_end(args); name->start -= n; memcpy(name->start, buffer, n); } static void FORMAT_ATTR(2) append(struct type_name *name, const char *fmt, ...) { static char buffer[512]; int n; va_list args; va_start(args, fmt); n = vsprintf(buffer, fmt, args); va_end(args); memcpy(name->end, buffer, n); name->end += n; } static struct ctype_name { struct symbol *sym; const char *name; const char *suffix; } typenames[] = { { & char_ctype, "char", "" }, { &schar_ctype, "signed char", "" }, { &uchar_ctype, "unsigned char", "" }, { & short_ctype, "short", "" }, { &sshort_ctype, "signed short", "" }, { &ushort_ctype, "unsigned short", "" }, { & int_ctype, "int", "" }, { &sint_ctype, "signed int", "" }, { &uint_ctype, "unsigned int", "U" }, { & long_ctype, "long", "L" }, { &slong_ctype, "signed long", "L" }, { &ulong_ctype, "unsigned long", "UL" }, { & llong_ctype, "long long", "LL" }, { &sllong_ctype, "signed long long", "LL" }, { &ullong_ctype, "unsigned long long", "ULL" }, { & lllong_ctype, "long long long", "LLL" }, { &slllong_ctype, "signed long long long", "LLL" }, { &ulllong_ctype, "unsigned long long long", "ULLL" }, { &void_ctype, "void", "" }, { &bool_ctype, "bool", "" }, { &float_ctype, "float", "F" }, { &double_ctype, "double", "" }, { &ldouble_ctype,"long double", "L" }, { &incomplete_ctype, "incomplete type", "" }, { &int_type, "abstract int", "" }, { &fp_type, "abstract fp", "" }, { &label_ctype, "label type", "" }, { &bad_ctype, "bad type", "" }, }; const char *builtin_typename(struct symbol *sym) { int i; for (i = 0; i < ARRAY_SIZE(typenames); i++) if (typenames[i].sym == sym) return typenames[i].name; return NULL; } const char *builtin_type_suffix(struct symbol *sym) { int i; for (i = 0; i < ARRAY_SIZE(typenames); i++) if (typenames[i].sym == sym) return typenames[i].suffix; return NULL; } const char *builtin_ctypename(struct ctype *ctype) { int i; for (i = 0; i < ARRAY_SIZE(typenames); i++) if (&typenames[i].sym->ctype == ctype) return typenames[i].name; return NULL; } static void do_show_type(struct symbol *sym, struct type_name *name) { const char *typename; unsigned long mod = 0; struct ident *as = NULL; int was_ptr = 0; int restr = 0; int fouled = 0; deeper: if (!sym || (sym->type != SYM_NODE && sym->type != SYM_ARRAY && sym->type != SYM_BITFIELD)) { const char *s; size_t len; if (as) prepend(name, "%s ", show_as(as)); if (sym->type == SYM_BASETYPE || sym->type == SYM_ENUM) mod &= ~MOD_SPECIFIER; s = modifier_string(mod); len = strlen(s); name->start -= len; memcpy(name->start, s, len); mod = 0; as = NULL; } if (!sym) goto out; if ((typename = builtin_typename(sym))) { int len = strlen(typename); if (name->start != name->end) *--name->start = ' '; name->start -= len; memcpy(name->start, typename, len); goto out; } /* Prepend */ switch (sym->type) { case SYM_PTR: prepend(name, "*"); mod = sym->ctype.modifiers; as = sym->ctype.as; was_ptr = 1; break; case SYM_FN: if (was_ptr) { prepend(name, "( "); append(name, " )"); was_ptr = 0; } append(name, "( ... )"); break; case SYM_STRUCT: if (name->start != name->end) *--name->start = ' '; prepend(name, "struct %s", show_ident(sym->ident)); goto out; case SYM_UNION: if (name->start != name->end) *--name->start = ' '; prepend(name, "union %s", show_ident(sym->ident)); goto out; case SYM_ENUM: prepend(name, "enum %s ", show_ident(sym->ident)); break; case SYM_NODE: if (sym->ident) append(name, "%s", show_ident(sym->ident)); mod |= sym->ctype.modifiers; combine_address_space(sym->pos, &as, sym->ctype.as); break; case SYM_BITFIELD: mod |= sym->ctype.modifiers; combine_address_space(sym->pos, &as, sym->ctype.as); append(name, ":%d", sym->bit_size); break; case SYM_LABEL: append(name, "label(%s:%p)", show_ident(sym->ident), sym); return; case SYM_ARRAY: mod |= sym->ctype.modifiers; combine_address_space(sym->pos, &as, sym->ctype.as); if (was_ptr) { prepend(name, "( "); append(name, " )"); was_ptr = 0; } append(name, "[%lld]", get_expression_value(sym->array_size)); break; case SYM_RESTRICT: if (!sym->ident) { restr = 1; break; } if (name->start != name->end) *--name->start = ' '; prepend(name, "restricted %s", show_ident(sym->ident)); goto out; case SYM_FOULED: fouled = 1; break; default: if (name->start != name->end) *--name->start = ' '; prepend(name, "unknown type %d", sym->type); goto out; } sym = sym->ctype.base_type; goto deeper; out: if (restr) prepend(name, "restricted "); if (fouled) prepend(name, "fouled "); // strip trailing space if (name->end > name->start && name->end[-1] == ' ') name->end--; } void show_type(struct symbol *sym) { char array[200]; struct type_name name; name.start = name.end = array+100; do_show_type(sym, &name); *name.end = 0; printf("%s", name.start); } const char *show_typename(struct symbol *sym) { static char array[200]; struct type_name name; name.start = name.end = array+100; do_show_type(sym, &name); *name.end = 0; return name.start; } void show_symbol(struct symbol *sym) { struct symbol *type; if (!sym) return; if (sym->ctype.alignment) printf(".align %ld\n", sym->ctype.alignment); show_type(sym); type = sym->ctype.base_type; if (!type) { printf("\n"); return; } /* * Show actual implementation information */ switch (type->type) { struct symbol *member; case SYM_STRUCT: case SYM_UNION: printf(" {\n"); FOR_EACH_PTR(type->symbol_list, member) { show_struct_member(member); } END_FOR_EACH_PTR(member); printf("}\n"); break; case SYM_FN: { struct statement *stmt = type->stmt; printf("\n"); if (stmt) { int val; val = show_statement(stmt); if (val) printf("\tmov.%d\t\tretval,%d\n", stmt->ret->bit_size, val); printf("\tret\n"); } break; } default: printf("\n"); break; } if (sym->initializer) { printf(" = \n"); show_expression(sym->initializer); } } static int show_symbol_init(struct symbol *sym); static int new_pseudo(void) { static int nr = 0; return ++nr; } static int new_label(void) { static int label = 0; return ++label; } static void show_switch_statement(struct statement *stmt) { int val = show_expression(stmt->switch_expression); struct symbol *sym; printf("\tswitch v%d\n", val); /* * Debugging only: Check that the case list is correct * by printing it out. * * This is where a _real_ back-end would go through the * cases to decide whether to use a lookup table or a * series of comparisons etc */ printf("# case table:\n"); FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) { struct statement *case_stmt = sym->stmt; struct expression *expr = case_stmt->case_expression; struct expression *to = case_stmt->case_to; if (!expr) { printf(" default"); } else { if (expr->type == EXPR_VALUE) { printf(" case %lld", expr->value); if (to) { if (to->type == EXPR_VALUE) { printf(" .. %lld", to->value); } else { printf(" .. what?"); } } } else printf(" what?"); } printf(": .L%p\n", sym); } END_FOR_EACH_PTR(sym); printf("# end case table\n"); show_statement(stmt->switch_statement); if (stmt->switch_break->used) printf(".L%p:\n", stmt->switch_break); } static void show_symbol_decl(struct symbol_list *syms) { struct symbol *sym; FOR_EACH_PTR(syms, sym) { show_symbol_init(sym); } END_FOR_EACH_PTR(sym); } static int show_return_stmt(struct statement *stmt); /* * Print out a statement */ int show_statement(struct statement *stmt) { if (!stmt) return 0; switch (stmt->type) { case STMT_DECLARATION: show_symbol_decl(stmt->declaration); return 0; case STMT_RETURN: return show_return_stmt(stmt); case STMT_COMPOUND: { struct statement *s; int last = 0; if (stmt->inline_fn) { show_statement(stmt->args); printf("\tbegin_inline \t%s\n", show_ident(stmt->inline_fn->ident)); } FOR_EACH_PTR(stmt->stmts, s) { last = show_statement(s); } END_FOR_EACH_PTR(s); if (stmt->ret) { int addr, bits; printf(".L%p:\n", stmt->ret); addr = show_symbol_expr(stmt->ret); bits = stmt->ret->bit_size; last = new_pseudo(); printf("\tld.%d\t\tv%d,[v%d]\n", bits, last, addr); } if (stmt->inline_fn) printf("\tend_inlined\t%s\n", show_ident(stmt->inline_fn->ident)); return last; } case STMT_EXPRESSION: return show_expression(stmt->expression); case STMT_IF: { int val, target; struct expression *cond = stmt->if_conditional; /* This is only valid if nobody can jump into the "dead" statement */ #if 0 if (cond->type == EXPR_VALUE) { struct statement *s = stmt->if_true; if (!cond->value) s = stmt->if_false; show_statement(s); break; } #endif val = show_expression(cond); target = new_label(); printf("\tje\t\tv%d,.L%d\n", val, target); show_statement(stmt->if_true); if (stmt->if_false) { int last = new_label(); printf("\tjmp\t\t.L%d\n", last); printf(".L%d:\n", target); target = last; show_statement(stmt->if_false); } printf(".L%d:\n", target); break; } case STMT_SWITCH: show_switch_statement(stmt); break; case STMT_CASE: printf(".L%p:\n", stmt->case_label); show_statement(stmt->case_statement); break; case STMT_ITERATOR: { struct statement *pre_statement = stmt->iterator_pre_statement; struct expression *pre_condition = stmt->iterator_pre_condition; struct statement *statement = stmt->iterator_statement; struct statement *post_statement = stmt->iterator_post_statement; struct expression *post_condition = stmt->iterator_post_condition; int val, loop_top = 0, loop_bottom = 0; show_symbol_decl(stmt->iterator_syms); show_statement(pre_statement); if (pre_condition) { if (pre_condition->type == EXPR_VALUE) { if (!pre_condition->value) { loop_bottom = new_label(); printf("\tjmp\t\t.L%d\n", loop_bottom); } } else { loop_bottom = new_label(); val = show_expression(pre_condition); printf("\tje\t\tv%d, .L%d\n", val, loop_bottom); } } if (!post_condition || post_condition->type != EXPR_VALUE || post_condition->value) { loop_top = new_label(); printf(".L%d:\n", loop_top); } show_statement(statement); if (stmt->iterator_continue->used) printf(".L%p:\n", stmt->iterator_continue); show_statement(post_statement); if (!post_condition) { printf("\tjmp\t\t.L%d\n", loop_top); } else if (post_condition->type == EXPR_VALUE) { if (post_condition->value) printf("\tjmp\t\t.L%d\n", loop_top); } else { val = show_expression(post_condition); printf("\tjne\t\tv%d, .L%d\n", val, loop_top); } if (stmt->iterator_break->used) printf(".L%p:\n", stmt->iterator_break); if (loop_bottom) printf(".L%d:\n", loop_bottom); break; } case STMT_NONE: break; case STMT_LABEL: printf(".L%p:\n", stmt->label_identifier); show_statement(stmt->label_statement); break; case STMT_GOTO: if (stmt->goto_expression) { int val = show_expression(stmt->goto_expression); printf("\tgoto\t\t*v%d\n", val); } else { printf("\tgoto\t\t.L%p\n", stmt->goto_label); } break; case STMT_ASM: printf("\tasm( .... )\n"); break; case STMT_CONTEXT: { int val = show_expression(stmt->expression); printf("\tcontext( %d )\n", val); break; } case STMT_RANGE: { int val = show_expression(stmt->range_expression); int low = show_expression(stmt->range_low); int high = show_expression(stmt->range_high); printf("\trange( %d %d-%d)\n", val, low, high); break; } } return 0; } static int show_call_expression(struct expression *expr) { struct symbol *direct; struct expression *arg, *fn; int fncall, retval; int framesize; if (!expr->ctype) { warning(expr->pos, "\tcall with no type!"); return 0; } framesize = 0; FOR_EACH_PTR_REVERSE(expr->args, arg) { int new = show_expression(arg); int size = arg->ctype->bit_size; printf("\tpush.%d\t\tv%d\n", size, new); framesize += bits_to_bytes(size); } END_FOR_EACH_PTR_REVERSE(arg); fn = expr->fn; /* Remove dereference, if any */ direct = NULL; if (fn->type == EXPR_PREOP) { if (fn->unop->type == EXPR_SYMBOL) { struct symbol *sym = fn->unop->symbol; if (sym->ctype.base_type->type == SYM_FN) direct = sym; } } if (direct) { printf("\tcall\t\t%s\n", show_ident(direct->ident)); } else { fncall = show_expression(fn); printf("\tcall\t\t*v%d\n", fncall); } if (framesize) printf("\tadd.%d\t\tvSP,vSP,$%d\n", bits_in_pointer, framesize); retval = new_pseudo(); printf("\tmov.%d\t\tv%d,retval\n", expr->ctype->bit_size, retval); return retval; } static int show_comma(struct expression *expr) { show_expression(expr->left); return show_expression(expr->right); } static int show_binop(struct expression *expr) { int left = show_expression(expr->left); int right = show_expression(expr->right); int new = new_pseudo(); const char *opname; static const char *name[] = { ['+'] = "add", ['-'] = "sub", ['*'] = "mul", ['/'] = "div", ['%'] = "mod", ['&'] = "and", ['|'] = "lor", ['^'] = "xor" }; unsigned int op = expr->op; opname = show_special(op); if (op < ARRAY_SIZE(name)) opname = name[op]; printf("\t%s.%d\t\tv%d,v%d,v%d\n", opname, expr->ctype->bit_size, new, left, right); return new; } static int show_slice(struct expression *expr) { int target = show_expression(expr->base); int new = new_pseudo(); printf("\tslice.%d\t\tv%d,v%d,%d\n", expr->r_nrbits, target, new, expr->r_bitpos); return new; } static int show_regular_preop(struct expression *expr) { int target = show_expression(expr->unop); int new = new_pseudo(); static const char *name[] = { ['!'] = "nonzero", ['-'] = "neg", ['~'] = "not", }; unsigned int op = expr->op; const char *opname; opname = show_special(op); if (op < ARRAY_SIZE(name)) opname = name[op]; printf("\t%s.%d\t\tv%d,v%d\n", opname, expr->ctype->bit_size, new, target); return new; } /* * FIXME! Not all accesses are memory loads. We should * check what kind of symbol is behind the dereference. */ static int show_address_gen(struct expression *expr) { return show_expression(expr->unop); } static int show_load_gen(int bits, struct expression *expr, int addr) { int new = new_pseudo(); printf("\tld.%d\t\tv%d,[v%d]\n", bits, new, addr); return new; } static void show_store_gen(int bits, int value, struct expression *expr, int addr) { /* FIXME!!! Bitfield store! */ printf("\tst.%d\t\tv%d,[v%d]\n", bits, value, addr); } static int show_assignment(struct expression *expr) { struct expression *target = expr->left; int val, addr, bits; if (!expr->ctype) return 0; bits = expr->ctype->bit_size; val = show_expression(expr->right); addr = show_address_gen(target); show_store_gen(bits, val, target, addr); return val; } static int show_return_stmt(struct statement *stmt) { struct expression *expr = stmt->ret_value; struct symbol *target = stmt->ret_target; if (expr && expr->ctype) { int val = show_expression(expr); int bits = expr->ctype->bit_size; int addr = show_symbol_expr(target); show_store_gen(bits, val, NULL, addr); } printf("\tret\t\t(%p)\n", target); return 0; } static int show_initialization(struct symbol *sym, struct expression *expr) { int val, addr, bits; if (!expr->ctype) return 0; bits = expr->ctype->bit_size; val = show_expression(expr); addr = show_symbol_expr(sym); // FIXME! The "target" expression is for bitfield store information. // Leave it NULL, which works fine. show_store_gen(bits, val, NULL, addr); return 0; } static int show_access(struct expression *expr) { int addr = show_address_gen(expr); return show_load_gen(expr->ctype->bit_size, expr, addr); } static int show_inc_dec(struct expression *expr, int postop) { int addr = show_address_gen(expr->unop); int retval, new; const char *opname = expr->op == SPECIAL_INCREMENT ? "add" : "sub"; int bits = expr->ctype->bit_size; retval = show_load_gen(bits, expr->unop, addr); new = retval; if (postop) new = new_pseudo(); printf("\t%s.%d\t\tv%d,v%d,$1\n", opname, bits, new, retval); show_store_gen(bits, new, expr->unop, addr); return retval; } static int show_preop(struct expression *expr) { /* * '*' is an lvalue access, and is fundamentally different * from an arithmetic operation. Maybe it should have an * expression type of its own.. */ if (expr->op == '*') return show_access(expr); if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT) return show_inc_dec(expr, 0); return show_regular_preop(expr); } static int show_postop(struct expression *expr) { return show_inc_dec(expr, 1); } static int show_symbol_expr(struct symbol *sym) { int new = new_pseudo(); if (sym->initializer && sym->initializer->type == EXPR_STRING) return show_string_expr(sym->initializer); if (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_EXTERN | MOD_STATIC)) { printf("\tmovi.%d\t\tv%d,$%s\n", bits_in_pointer, new, show_ident(sym->ident)); return new; } if (sym->ctype.modifiers & MOD_ADDRESSABLE) { printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new, 0LL); return new; } printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", bits_in_pointer, new, show_ident(sym->ident), sym); return new; } static int show_symbol_init(struct symbol *sym) { struct expression *expr = sym->initializer; if (expr) { int val, addr, bits; bits = expr->ctype->bit_size; val = show_expression(expr); addr = show_symbol_expr(sym); show_store_gen(bits, val, NULL, addr); } return 0; } static int show_cast_expr(struct expression *expr) { struct symbol *old_type, *new_type; int op = show_expression(expr->cast_expression); int oldbits, newbits; int new, is_signed; old_type = expr->cast_expression->ctype; new_type = expr->cast_type; oldbits = old_type->bit_size; newbits = new_type->bit_size; if (oldbits >= newbits) return op; new = new_pseudo(); is_signed = is_signed_type(old_type); if (is_signed) { printf("\tsext%d.%d\tv%d,v%d\n", oldbits, newbits, new, op); } else { printf("\tandl.%d\t\tv%d,v%d,$%lu\n", newbits, new, op, (1UL << oldbits)-1); } return new; } static int show_value(struct expression *expr) { int new = new_pseudo(); unsigned long long value = expr->value; printf("\tmovi.%d\t\tv%d,$%llu\n", expr->ctype->bit_size, new, value); return new; } static int show_fvalue(struct expression *expr) { int new = new_pseudo(); long double value = expr->fvalue; printf("\tmovf.%d\t\tv%d,$%Le\n", expr->ctype->bit_size, new, value); return new; } static int show_string_expr(struct expression *expr) { int new = new_pseudo(); printf("\tmovi.%d\t\tv%d,&%s\n", bits_in_pointer, new, show_string(expr->string)); return new; } static int show_label_expr(struct expression *expr) { int new = new_pseudo(); printf("\tmovi.%d\t\tv%d,.L%p\n",bits_in_pointer, new, expr->label_symbol); return new; } static int show_conditional_expr(struct expression *expr) { int cond = show_expression(expr->conditional); int valt = show_expression(expr->cond_true); int valf = show_expression(expr->cond_false); int new = new_pseudo(); printf("[v%d]\tcmov.%d\t\tv%d,v%d,v%d\n", cond, expr->ctype->bit_size, new, valt, valf); return new; } static int show_statement_expr(struct expression *expr) { return show_statement(expr->statement); } static int show_position_expr(struct expression *expr, struct symbol *base) { int new = show_expression(expr->init_expr); struct symbol *ctype = expr->init_expr->ctype; int bit_offset; bit_offset = ctype ? ctype->bit_offset : -1; printf("\tinsert v%d at [%d:%d] of %s\n", new, expr->init_offset, bit_offset, show_ident(base->ident)); return 0; } static int show_initializer_expr(struct expression *expr, struct symbol *ctype) { struct expression *entry; FOR_EACH_PTR(expr->expr_list, entry) { again: // Nested initializers have their positions already // recursively calculated - just output them too if (entry->type == EXPR_INITIALIZER) { show_initializer_expr(entry, ctype); continue; } // Initializer indexes and identifiers should // have been evaluated to EXPR_POS if (entry->type == EXPR_IDENTIFIER) { printf(" AT '%s':\n", show_ident(entry->expr_ident)); entry = entry->ident_expression; goto again; } if (entry->type == EXPR_INDEX) { printf(" AT '%d..%d:\n", entry->idx_from, entry->idx_to); entry = entry->idx_expression; goto again; } if (entry->type == EXPR_POS) { show_position_expr(entry, ctype); continue; } show_initialization(ctype, entry); } END_FOR_EACH_PTR(entry); return 0; } int show_symbol_expr_init(struct symbol *sym) { struct expression *expr = sym->initializer; if (expr) show_expression(expr); return show_symbol_expr(sym); } /* * Print out an expression. Return the pseudo that contains the * variable. */ int show_expression(struct expression *expr) { if (!expr) return 0; if (!expr->ctype) { struct position *pos = &expr->pos; printf("\tno type at %s:%d:%d\n", stream_name(pos->stream), pos->line, pos->pos); return 0; } switch (expr->type) { case EXPR_CALL: return show_call_expression(expr); case EXPR_ASSIGNMENT: return show_assignment(expr); case EXPR_COMMA: return show_comma(expr); case EXPR_BINOP: case EXPR_COMPARE: case EXPR_LOGICAL: return show_binop(expr); case EXPR_PREOP: return show_preop(expr); case EXPR_POSTOP: return show_postop(expr); case EXPR_SYMBOL: return show_symbol_expr(expr->symbol); case EXPR_DEREF: case EXPR_SIZEOF: case EXPR_PTRSIZEOF: case EXPR_ALIGNOF: case EXPR_OFFSETOF: warning(expr->pos, "invalid expression after evaluation"); return 0; case EXPR_CAST: case EXPR_FORCE_CAST: case EXPR_IMPLIED_CAST: return show_cast_expr(expr); case EXPR_VALUE: return show_value(expr); case EXPR_FVALUE: return show_fvalue(expr); case EXPR_STRING: return show_string_expr(expr); case EXPR_INITIALIZER: return show_initializer_expr(expr, expr->ctype); case EXPR_SELECT: case EXPR_CONDITIONAL: return show_conditional_expr(expr); case EXPR_STATEMENT: return show_statement_expr(expr); case EXPR_LABEL: return show_label_expr(expr); case EXPR_SLICE: return show_slice(expr); // None of these should exist as direct expressions: they are only // valid as sub-expressions of initializers. case EXPR_POS: warning(expr->pos, "unable to show plain initializer position expression"); return 0; case EXPR_IDENTIFIER: warning(expr->pos, "unable to show identifier expression"); return 0; case EXPR_INDEX: warning(expr->pos, "unable to show index expression"); return 0; case EXPR_TYPE: warning(expr->pos, "unable to show type expression"); return 0; case EXPR_ASM_OPERAND: warning(expr->pos, "unable to show asm operand expression"); return 0; } return 0; }