aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/show-parse.c
diff options
authorLinus Torvalds <torvalds@home.transmeta.com>2003-04-06 23:24:10 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-07 21:00:17 -0700
commit20e0646d9239ea6fa22dcd033221883c3eddddf3 (patch)
tree635bc15db50c3bc65e5e89362d3cb4dfecb13cbb /show-parse.c
parent1460a6fb9235041fd4242497e5d3e7e53a7ad6ff (diff)
downloadsparse-dev-20e0646d9239ea6fa22dcd033221883c3eddddf3.tar.gz
Show the expression parse tree as a sick kind of assembly language, which
bears almost no resemblance to any _sane_ assembly language, but which gives a much better idea of what a back-end might actually do. It also (since it has to linearize function calls and get argument sizes right and so on) ends up being a pretty good way to see obvious breakage in the parse tree. If you can just ignore the strangeness of the "assembly language". My favourite "instructions": [vP] cmov vT,vA,vB here vP is a virtual register that acts as a "predicate" for the cmov, and it will move the value of vA into vT if vP is non-zero, otherwise vB. It matches the C expression vT = vP ? vA : vB. It also has the "notzero" instruction: notzero vT,vA which sets vT to 0/1 depending on whether vA is nonzero/zero. It matches the C expression vT = !vA. Think of it as a three-register machine designed for REALLY stupid C compilers ;)
Diffstat (limited to 'show-parse.c')
-rw-r--r--show-parse.c216
1 files changed, 147 insertions, 69 deletions
diff --git a/show-parse.c b/show-parse.c
index c1d79b75..87a22813 100644
--- a/show-parse.c
+++ b/show-parse.c
@@ -19,6 +19,7 @@
#include "symbol.h"
#include "scope.h"
#include "expression.h"
+#include "target.h"
/*
* Symbol type printout. The type system is by far the most
@@ -240,6 +241,9 @@ void show_symbol(struct symbol *sym)
{
struct symbol *type;
+ if (!sym)
+ return;
+
show_type(sym);
type = sym->ctype.base_type;
if (!type)
@@ -425,12 +429,6 @@ void show_statement_list(struct statement_list *stmt, const char *sep)
statement_iterate(stmt, show_one_statement, (void *)sep);
}
-static void show_size(struct symbol *sym)
-{
- if (sym)
- printf("%d:%ld", sym->bit_size, sym->ctype.alignment);
-}
-
static void show_one_expression(struct expression *expr, void *sep, int flags)
{
show_expression(expr);
@@ -451,14 +449,16 @@ static int new_pseudo(void)
static int show_call_expression(struct expression *expr)
{
- int pseudoarg[45];
struct expression *arg, *fn;
int fncall, retval;
- int count = 0, i;
+ int framesize;
- FOR_EACH_PTR(expr->args, arg) {
+ framesize = 0;
+ FOR_EACH_PTR_REVERSE(expr->args, arg) {
int new = show_expression(arg);
- pseudoarg[count++] = new;
+ int size = arg->ctype->bit_size;
+ printf("\tpush.%d\t\tv%d\n", size, new);
+ framesize += size >> 3;
} END_FOR_EACH_PTR;
fn = expr->fn;
@@ -467,31 +467,12 @@ static int show_call_expression(struct expression *expr)
fn = fn->unop;
fncall = show_expression(fn);
retval = new_pseudo();
- printf("v%d = call *v%d(", retval, fncall);
- for (i = 0; i < count; i++)
- printf("v%d%s", pseudoarg[i], (i == count-1) ? "" : ", ");
- printf(")\n");
- return retval;
-}
-
-static int show_assignment(struct expression *expr)
-{
- int src = show_expression(expr->right);
- struct expression *target = expr->left;
- int dst;
-
- /* Is it a regular dereferece? */
- if (target->type == EXPR_PREOP) {
- dst = show_expression(target->unop);
- printf("store(v%d,v%d)\n", src, dst);
- return src;
- }
- /* Bitfield.. */
- dst = show_expression(target->address);
- printf("bit_insert(v%d,v%d[%d-%d]\n", src, dst,
- target->bitpos, target->bitpos + target->nrbits);
- return src;
+ printf("\tcall\t\t*v%d\n", fncall);
+ if (framesize)
+ printf("\tadd.%d\t\tvSP,vSP,$%d\n", BITS_IN_POINTER, framesize);
+ printf("\tmov.%d\t\tv%d,retval\n", expr->ctype->bit_size, retval);
+ return retval;
}
static int show_binop(struct expression *expr)
@@ -499,74 +480,171 @@ static int show_binop(struct expression *expr)
int left = show_expression(expr->left);
int right = show_expression(expr->right);
int new = new_pseudo();
-
- printf("v%d = v%d %s v%d\n", new, left, show_special(expr->op), right);
+ const char *opname;
+ static const char *name[] = {
+ ['+'] = "add", ['-'] = "sub",
+ ['*'] = "mul", ['/'] = "div",
+ ['%'] = "mod"
+ };
+ 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_preop(struct expression *expr)
+static int show_regular_preop(struct expression *expr)
{
- int op = show_expression(expr->unop);
+ 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;
- printf("v%d = %sv%d\n", new, show_special(expr->op), op);
+ 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;
-}
+}
-static int show_postop(struct expression *expr)
+/*
+ * 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 op = show_expression(expr->unop);
int new = new_pseudo();
- printf("v%d = v%d%s\n", new, op, show_special(expr->op));
+ 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", bits, new, new, 1ULL << expr->nrbits);
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 = 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_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 expression *expr)
{
int new = new_pseudo();
- printf("v%d = address of '%s'\n", new, show_ident(expr->symbol_name));
+ printf("\tmovi.%d\t\tv%d,$%s\n", BITS_IN_POINTER, new, show_ident(expr->symbol_name));
return new;
}
+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;
+ int new, is_signed;
- oldbits = expr->cast_expression->ctype->bit_size;
- newbits = expr->cast_type->bit_size;
- if (oldbits == newbits)
+ 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();
- printf("v%d = <cast from %d to %d bits> v%d\n",
- new, oldbits, newbits, op);
+ 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 type_is_signed(struct symbol *sym)
-{
- while (sym->type != SYM_BASETYPE)
- sym = sym->ctype.base_type;
- return !(sym->ctype.modifiers & MOD_UNSIGNED);
-}
-
static int show_value(struct expression *expr)
{
int new = new_pseudo();
- struct symbol *ctype = expr->ctype;
unsigned long long value = expr->value;
- unsigned long long mask = 1ULL << (ctype->bit_size-1);
- if (value & mask) {
- if (type_is_signed(ctype)) {
- long long svalue = value | ~(mask-1);
- printf("v%d = %lld\n", new, svalue);
- return new;
- }
- }
- printf("v%d = %llu\n", new, value);
+ printf("\tmovi.%d\t\tv%d,$%llu\n", expr->ctype->bit_size, new, value);
return new;
}
@@ -574,7 +652,7 @@ static int show_string_expr(struct expression *expr)
{
int new = new_pseudo();
- printf("v%d = %s\n", new, show_string(expr->string));
+ printf("\tmovi.%d\t\tv%d,&%s\n", BITS_IN_POINTER, new, show_string(expr->string));
return new;
}
@@ -597,7 +675,7 @@ static int show_conditional_expr(struct expression *expr)
if (!true)
true = cond;
- printf("v%d = v%d ? v%d : v%d\n", new, cond, true, false);
+ printf("[v%d]\tcmov.%d\t\tv%d,v%d,v%d\n", cond, expr->ctype->bit_size, new, true, false);
return new;
}