blob: 1333e301c15123eb0a34ebd9195befb9ac04f032 [file] [log] [blame]
/*
* sparse/show-parse.c
*
* Copyright (C) 2003 Transmeta Corp.
* 2003-2004 Linus Torvalds
*
* Licensed under the Open Software License version 1.1
*
* Print out results of parsing for debugging and testing.
*/
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#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: %d) %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), 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_SIGNED, "[signed]"},
{MOD_UNSIGNED, "[unsigned]"},
{MOD_CHAR, "[char]"},
{MOD_SHORT, "[short]"},
{MOD_LONG, "[long]"},
{MOD_LONGLONG, "[long long]"},
{MOD_LONGLONGLONG, "[long long long]"},
{MOD_TYPEDEF, "[typedef]"},
{MOD_TLS, "[tls]"},
{MOD_INLINE, "inline"},
{MOD_ADDRESSABLE, "[addressable]"},
{MOD_NOCAST, "[nocast]"},
{MOD_NODEREF, "[noderef]"},
{MOD_ACCESSED, "[accessed]"},
{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);
}
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;
} 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" },
{ &slong_ctype, "signed long" },
{ & long_ctype, "long" },
{ &ulong_ctype, "unsigned long" },
{ & llong_ctype, "long long" },
{ &sllong_ctype, "signed long long" },
{ &ullong_ctype, "unsigned long long" },
{ & lllong_ctype, "long long long" },
{ &slllong_ctype, "signed long long long" },
{ &ulllong_ctype, "unsigned long long long" },
{ &void_ctype, "void" },
{ &bool_ctype, "bool" },
{ &string_ctype, "string" },
{ &float_ctype, "float" },
{ &double_ctype, "double" },
{ &ldouble_ctype,"long double" },
{ &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_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;
int as = 0;
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, "<asn:%d>", as);
s = modifier_string(mod);
len = strlen(s);
name->start -= len;
memcpy(name->start, s, len);
mod = 0;
as = 0;
}
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:
append(name, "%s", show_ident(sym->ident));
mod |= sym->ctype.modifiers;
as |= sym->ctype.as;
break;
case SYM_BITFIELD:
mod |= sym->ctype.modifiers;
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;
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 ");
}
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->bb_target);
} 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->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(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->bb_target);
}
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, 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_fvalue(struct expression *expr)
{
int new = new_pseudo();
long double value = expr->fvalue;
printf("\tmovf.%d\t\tv%d,$%Lf\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 true = show_expression(expr->cond_true);
int false = 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, 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_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;
}
return 0;
}