/* * sparse/show-parse.c * * Copyright (C) 2003 Transmeta Corp. * 2003 Linus Torvalds * * Licensed under the Open Software License version 1.1 * * Print out results of parsing for debugging and testing. */ #include #include #include #include #include #include #include #include "lib.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 void do_debug_symbol(struct symbol *sym, int indent) { static const char indent_string[] = " "; static const char *typestr[] = { "base", "node", "ptr.", "fn..", "arry", "strt", "unin", "enum", "tdef", "tpof", "memb", "bitf", "labl" }; if (!sym) return; fprintf(stderr, "%.*s%s%3d:%lu %lx %s (as: %d, context: %x:%x) %p (%s:%d:%d)\n", indent, indent_string, typestr[sym->type], sym->bit_size, sym->ctype.alignment, sym->ctype.modifiers, show_ident(sym->ident), sym->ctype.as, sym->ctype.context, sym->ctype.contextmask, sym, input_streams[sym->pos.stream].name, sym->pos.line, sym->pos.pos); if (sym->type == SYM_FN) { int i = 1; struct symbol *arg; 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; } 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]; char *p = buffer; const char *res,**ptr, *names[] = { "auto", "register", "static", "extern", "const", "volatile", "[signed]", "[unsigned]", "[char]", "[short]", "[long]", "[long]", "[typdef]", "[structof]", "[unionof]", "[enum]", "[typeof]", "[attribute]", "inline", "[addressable]", "[nocast]", "[noderef]", "[accessed]", "[toplevel]", "[label]", "[assigned]", "[type]", "[safe]", "[usertype]", "[force]", NULL }; ptr = names; while ((res = *ptr++) != NULL) { if (mod & 1) { char c; while ((c = *res++) != '\0') *p++ = c; *p++ = ' '; } mod >>= 1; } *p = 0; return buffer; } void show_struct_member(struct symbol *sym, void *data, int flags) { if (flags & ITERATE_FIRST) printf(" {\n\t"); printf("%s:%d:%ld at offset %ld", show_ident(sym->ident), sym->bit_size, sym->ctype.alignment, sym->offset); if (sym->fieldwidth) printf("[%d..%d]", sym->bit_offset, sym->bit_offset+sym->fieldwidth-1); if (flags & ITERATE_LAST) printf("\n} "); else printf(", "); } static void show_one_symbol(struct symbol *sym, void *sep, int flags) { show_symbol(sym); if (!(flags & ITERATE_LAST)) printf("%s", (const char *)sep); } void show_symbol_list(struct symbol_list *list, const char *sep) { symbol_iterate(list, show_one_symbol, (void *)sep); } struct type_name { char *start; char *end; }; static void 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 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 void do_show_type(struct symbol *sym, struct type_name *name) { int i, modlen; const char *mod; static struct ctype_name { struct symbol *sym; char *name; } typenames[] = { { & char_ctype, "char" }, { &uchar_ctype, "unsigned char" }, { & short_ctype, "short" }, { &ushort_ctype, "unsigned short" }, { & int_ctype, "int" }, { &uint_ctype, "unsigned int" }, { & long_ctype, "long" }, { &ulong_ctype, "unsigned long" }, { & llong_ctype, "long long" }, { &ullong_ctype, "unsigned long long" }, { &void_ctype, "void" }, { &bool_ctype, "bool" }, { &string_ctype, "string" }, { &float_ctype, "float" }, { &double_ctype, "double" }, { &ldouble_ctype,"long double" }, }; if (!sym) return; for (i = 0; i < sizeof(typenames)/sizeof(typenames[0]); i++) { if (typenames[i].sym == sym) { int len = strlen(typenames[i].name); *--name->start = ' '; name->start -= len; memcpy(name->start, typenames[i].name, len); return; } } /* Prepend */ switch (sym->type) { case SYM_PTR: prepend(name, "*"); break; case SYM_FN: prepend(name, "( "); break; case SYM_STRUCT: prepend(name, "struct %s ", show_ident(sym->ident)); return; case SYM_UNION: prepend(name, "union %s ", show_ident(sym->ident)); return; case SYM_ENUM: prepend(name, "enum %s ", show_ident(sym->ident)); return; case SYM_NODE: append(name, "%s", show_ident(sym->ident)); break; case SYM_BITFIELD: append(name, ":%d", sym->fieldwidth); break; case SYM_LABEL: append(name, "label(%s:%p)", show_ident(sym->ident), sym); break; case SYM_ARRAY: break; default: prepend(name, "unknown type %d", sym->type); return; } mod = modifier_string(sym->ctype.modifiers); modlen = strlen(mod); name->start -= modlen; memcpy(name->start, mod, modlen); do_show_type(sym->ctype.base_type, name); /* Postpend */ if (sym->ctype.as) append(name, "", sym->ctype.as); switch (sym->type) { case SYM_PTR: return; case SYM_FN: append(name, " )( ... )"); return; case SYM_ARRAY: append(name, "[%lld]", get_expression_value(sym->array_size)); return; default: break; } } 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) return; /* * Show actual implementation information */ switch (type->type) { case SYM_STRUCT: symbol_iterate(type->symbol_list, show_struct_member, NULL); break; case SYM_UNION: symbol_iterate(type->symbol_list, show_struct_member, NULL); break; case SYM_FN: { struct statement *stmt = type->stmt; if (stmt) { int val; printf("\n"); val = show_statement(stmt); if (val) printf("\tmov.%d\t\tretval,%d\n", stmt->ret->bit_size, val); printf("\tret\n"); } break; } default: 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->bb_target); } END_FOR_EACH_PTR; printf("# end case table\n"); show_statement(stmt->switch_statement); if (stmt->switch_break->used) printf(".L%p:\n", stmt->switch_break->bb_target); } 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; } 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_RETURN: return show_return_stmt(stmt); case STMT_COMPOUND: { struct statement *s; int last = 0; show_symbol_decl(stmt->syms); FOR_EACH_PTR(stmt->stmts, s) { last = show_statement(s); } END_FOR_EACH_PTR; 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); } 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->bb_target); } break; case STMT_ASM: printf("\tasm( .... )\n"); break; } return 0; } static void show_one_statement(struct statement *stmt, void *sep, int flags) { show_statement(stmt); if (!(flags & ITERATE_LAST)) printf("%s", (const char *)sep); } void show_statement_list(struct statement_list *stmt, const char *sep) { statement_iterate(stmt, show_one_statement, (void *)sep); } static void show_one_expression(struct expression *expr, void *sep, int flags) { show_expression(expr); if (!(flags & ITERATE_LAST)) printf("%s", (const char *)sep); } void show_expression_list(struct expression_list *list, const char *sep) { expression_iterate(list, show_one_expression, (void *)sep); } static int show_call_expression(struct expression *expr) { struct symbol *direct; struct expression *arg, *fn; int fncall, retval; int framesize; if (!expr->ctype) { warn(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 += size >> 3; } END_FOR_EACH_PTR_REVERSE; 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_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 < sizeof(name)/sizeof(*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_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 < sizeof(name)/sizeof(*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) { if (expr->type == EXPR_PREOP) return show_expression(expr->unop); return show_expression(expr->address); } 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); if (expr->type == EXPR_PREOP) return new; /* bitfield load! */ if (expr->bitpos) printf("\tshr.%d\t\tv%d,v%d,$%d\n", bits, new, new, expr->bitpos); printf("\tandi.%d\t\tv%d,v%d,$%llu\n", bits, new, new, (1ULL << expr->nrbits)-1); 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->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, sym->value); 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 type_is_signed(struct symbol *sym) { if (sym->type == SYM_NODE) sym = sym->ctype.base_type; if (sym->type == SYM_PTR) return 0; return !(sym->ctype.modifiers & MOD_UNSIGNED); } 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 = type_is_signed(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_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_bitfield_expr(struct expression *expr) { return show_access(expr); } 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 true = show_expression(expr->cond_true); int false = show_expression(expr->cond_false); int new = new_pseudo(); if (!true) true = cond; printf("[v%d]\tcmov.%d\t\tv%d,v%d,v%d\n", cond, expr->ctype->bit_size, new, true, false); 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_sym; printf("\tinsert v%d at [%d:%d] of %s\n", new, expr->init_offset, ctype->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) { // Nested initializers have their positions already // recursively calculated - just output them too if (entry->type == EXPR_INITIALIZER) { show_initializer_expr(entry, ctype); continue; } // Ignore initializer indexes and identifiers - the // evaluator has taken them into account if (entry->type == EXPR_IDENTIFIER || entry->type == EXPR_INDEX) continue; if (entry->type == EXPR_POS) { show_position_expr(entry, ctype); continue; } show_initialization(ctype, entry); } END_FOR_EACH_PTR; 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", input_streams[pos->stream].name, 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_BINOP: case EXPR_COMMA: 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: warn(expr->pos, "invalid expression after evaluation"); return 0; case EXPR_CAST: return show_cast_expr(expr); case EXPR_VALUE: return show_value(expr); case EXPR_STRING: return show_string_expr(expr); case EXPR_BITFIELD: return show_bitfield_expr(expr); case EXPR_INITIALIZER: return show_initializer_expr(expr, expr->ctype); case EXPR_CONDITIONAL: return show_conditional_expr(expr); case EXPR_STATEMENT: return show_statement_expr(expr); case EXPR_LABEL: return show_label_expr(expr); // None of these should exist as direct expressions: they are only // valid as sub-expressions of initializers. case EXPR_POS: warn(expr->pos, "unable to show plain initializer position expression"); return 0; case EXPR_IDENTIFIER: warn(expr->pos, "unable to show identifier expression"); return 0; case EXPR_INDEX: warn(expr->pos, "unable to show index expression"); return 0; case EXPR_TYPE: warn(expr->pos, "unable to show type expression"); return 0; } return 0; }