/** Copyright Mark Shannon and the University of York 2006 */
#define STACK_MACHINE
#include "c.h"
#define NODEPTR_TYPE Node
#define OP_LABEL(p) ((p)->op)
#define LEFT_CHILD(p) ((p)->kids[0])
#define RIGHT_CHILD(p) ((p)->kids[1])
#define STATE_LABEL(p) ((p)->x.state)
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define REGS 0xffffffff
static void address(Symbol, Symbol, long);
static void defaddress(Symbol);
static void defconst(int, int, Value);
static void defstring(int, char *);
static void defsymbol(Symbol);
static void export(Symbol);
static void function(Symbol, Symbol [], Symbol [], int);
static void global(Symbol);
static void import(Symbol);
static void local(Symbol);
static void progbeg(int, char **);
static void progend(void);
static void segment(int);
static void space(int);
static void treeemit(Node forest);
extern void swtch(Symbol label);
extern Node stackgen(Node forest);
static int makeTemp(Symbol p)
{
if (!isscalar(p->type) || p->type->size == 8) {
p->sclass = AUTO;
return 0;
} else if (p->sclass == AUTO) {
if (p->addressed) {
return 0;
} else {
makeTemporary(p);
return 1;
}
} else if (p->sclass == REGISTER) {
makeTemporary(p);
return 1;
} else {
return 0;
}
}
static void local(Symbol p) {
if (!makeTemp(p)) {
mkauto(p);
}
}
static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
int i, size, varargs;
Node params;
offset = local_variable_count = 0;
params = stackParameters(caller, callee);
gencode(caller, callee);
optimise();
framesize = roundup(offset, 4);
treeemit(params);
emitcode();
}
static Node recalcNode(Node temp, Node calc) {
int op = specific(calc->op);
if (op == CNST + I) {
int lit = calc->syms[0]->u.c.v.i;
if (lit >= -(1<<16) && lit < (1<<16)) {
return calc;
} else {
return temp;
}
} else if (op == LSH + I) {
if (specific(calc->kids[1]->op) == CNST + I &&
calc->kids[1]->syms[0]->u.c.v.i == 2) {
int lhs_op = specific(calc->kids[0]->op);
if (lhs_op == INDIR + I) {
int addr_op = specific(calc->kids[0]->kids[0]->op);
if (addr_op == ADDRL + P || addr_op == ADDRG + P || addr_op == VREG + P) {
return calc;
}
}
}
}
return temp;
}
static int call_label = 0;
static int prevline = 0;
static int currentline = 0;
static void defconst(int suffix, int size, Value v) {
}
static void defaddress(Symbol p) {
// print(".word %s\n", p->x.name);
}
static void defstring(int n, char *str) {
}
static void export(Symbol p) {
}
static void import(Symbol p) {
// if (!isfunc(p->type))
// print(".extern %s %d\n", p->name, p->type->size);
}
static void defsymbol(Symbol p) {
if (p->scope == LABELS) {
p->x.name = stringf("L%s", p->name);
} else if (p->temporary) {
p->x.name = stringf("t%s", p->name);
} else if (p->generated) {
p->x.name = stringf("x%s", p->name);
} else {
p->x.name = stringf("%s", p->name);
}
}
static void address(Symbol q, Symbol p, long n) {
if (n)
q->x.name = stringf("%s%s%d", p->name, n >= 0 ? "+" : "", n);
else
q->x.name = p->name;
}
static void global(Symbol p) {
}
static void segment(int n) {
}
static void space(int n) {
}
static char *currentfile;
static int bitcount(unsigned mask) {
unsigned i, n = 0;
for (i = 1; i; i <<= 1)
if (mask&i)
n++;
return n;
}
/* stabinit - initialize stab output */
static void stabinit(char *file, int argc, char *argv[]) {
if (file) {
print("\\emph{%s}\n", file);
currentfile = file;
}
}
/* stabline - emit stab entry for source coordinate *cp */
static void stabline(Coordinate *cp) {
if (cp->file && cp->file != currentfile) {
print("\\emph{%s}\n", cp->file);
currentfile = cp->file;
}
currentline = cp->y;
}
/* stabsym - output a stab entry for symbol p */
static void stabsym(Symbol p) {
if (p == cfunc && IR->stabline)
(*IR->stabline)(&p->src);
}
static void progbeg(int argc, char *argv[]) {
print("\n");
print("\n");
}
static void blockbeg(Env* env) {
}
static void blockend(Env* env) {
}
struct left_right {
int left;
int right;
};
struct shape {
int length;
struct left_right items[1];
};
typedef struct shape* Shape;
static Shape new_shape(int length) {
Shape result = (Shape) allocate(length * sizeof(struct left_right) + sizeof(int), FUNC);
assert(length > 0);
result->length = length;
return result;
}
static int next_id = 1;
static int X_SCALE = 80;
static int Y_SCALE = 60;
static int X_OFFSET = 600;
static int Y_OFFSET = 20;
static int CHAR_SIZE = 8;
static int FONT_SIZE = 25;
static int Y_SPACING = 30;
static Shape treeWalk(Node p) {
int i, min_len, max_len;
int sep, half_sep;
Shape shape;
if (p->kids[1]) {
Shape shape0 = treeWalk(p->kids[0]);
Shape shape1 = treeWalk(p->kids[1]);
Shape deeper;
min_len = min(shape0->length, shape1->length);
sep = 0;
for (i = 0; i < min_len; i++) {
sep = max(sep, shape0->items[i].right + shape1->items[i].left);
}
half_sep = sep / 2;
max_len = max(shape0->length, shape1->length);
shape = new_shape(max_len + 1);
for (i = 0; i < min_len; i++) {
shape->items[i + 1].left = shape0->items[i].left + half_sep;
shape->items[i + 1].right = shape1->items[i].right + half_sep;
}
if (shape0->length > shape1->length) {
deeper = shape0;
offset = -half_sep;
} else {
deeper = shape1;
offset = half_sep;
}
for (i = min_len; i < max_len; i++) {
shape->items[i + 1].left = deeper->items[i].left - offset;
shape->items[i + 1].right = deeper->items[i].right + offset;
}
p->kids[0]->x.scratch = -half_sep;
p->kids[1]->x.scratch = half_sep;
} else if (p->kids[0]) {
Shape kid_shape = treeWalk(p->kids[0]);
shape = new_shape(kid_shape->length + 1);
for (i = 0; i < kid_shape->length; i++) {
shape->items[i + 1] = kid_shape->items[i];
}
p->kids[0]->x.scratch = 0;
} else {
shape = new_shape(1);
}
shape->items[0].left = X_SCALE;
shape->items[0].right = X_SCALE;
return shape;
}
char* getNodeText(Node p) {
char type;
if (optype(p->op) == I) type = 'I';
else if (optype(p->op) == U) type = 'U';
else if (optype(p->op) == F) type = 'F';
else if (optype(p->op) == P) type = 'P';
else if (optype(p->op) == B) type = 'B';
else type = 'X';
switch (generic(p->op)) {
case STACK:
return stringf("STACK%s", FONT_SIZE/2, p->syms[1]->x.name);
case COPY:
return stringf("COPY%s", FONT_SIZE/2, p->syms[1]->x.name);
case TUCK:
return stringf("TUCK%s", FONT_SIZE/2, p->syms[1]->x.name);
case VREG:
return "VREG";
case INDIR:
return "INDIR";
case ASGN:
return stringf("ASGN%c%d", type, opsize(p->op));
case LABEL:
return stringf("LABEL %s", p->syms[0]->x.name);
case ADDRL:
if (isdigit(p->syms[0]->name[0]))
return stringf("ADDRL t%s", p->syms[0]->name);
else
return stringf("ADDRL %s", p->syms[0]->name);
case ADDRG:
return stringf("ADDRG %s", p->syms[0]->x.name);
case ADDRF:
return stringf("ADDRF %s", p->syms[0]->name);
case BCOM:
return "NOT";
case CVF:
return stringf("CVF%c%d", type, opsize(p->op));
case CVI:
return stringf("CVI%c%d", type, opsize(p->op));
case CVP:
return stringf("CVP%c%d", type, opsize(p->op));
case CVU:
return stringf("CVU %c%d", type, opsize(p->op));
case NEG:
return "NEG";
case ADD:
return stringf("ADD%c%d", type, opsize(p->op));
case BAND:
return stringf("AND%c%d", type, opsize(p->op));
case BOR:
return stringf("OR%c%d", type, opsize(p->op));
case BXOR:
return stringf("XOR%c%d", type, opsize(p->op));
case LSH:
return "LSH";
case MOD:
return "MOD";
case DIV:
return "DIV";
case MUL:
return "MUL";
case RSH:
return "RSH";
case SUB:
return "SUB";
case EQ:
return stringf("BREQ %s", p->syms[0]->x.name);
case NE:
return stringf("BRNE %s", p->syms[0]->x.name);
case LT:
return stringf("BRLT %s", p->syms[0]->x.name);
case GT:
return stringf("BRGT %s", p->syms[0]->x.name);
case LE:
return stringf("BRLE %s", p->syms[0]->x.name);
case GE:
return stringf("BRGE %s", p->syms[0]->x.name);
case ARG:
return "ARG";
case CALL:
return "CALL";
case RET:
return "RETURN";
case JUMP:
return "JUMP";
case CNST:
if (optype(p->op) == I)
return stringf("CNST%c%d %d", type, opsize(p->op), p->syms[0]->u.c.v.i);
else
return stringf("CNST%c%d", type, opsize(p->op));
default:
return opname(generic(p->op));
}
}
int getTextSize(Node p) {
switch (generic(p->op)) {
case COPY: case TUCK:
return 5;
case STACK:
return 6;
default:
return strlen(getNodeText(p));
}
}
static void drawNode(Node p, int x, int y) {
int textSize = getTextSize(p);
print("\n");
print("", next_id++);
print("%s\n", getNodeText(p));
}
static void drawLine(int x1, int y1, int x2, int y2) {
print("\n",
(x1 + X_OFFSET), (y1 + Y_OFFSET), (x2 + X_OFFSET), (y2 + Y_OFFSET));
}
static void drawLines(Node p, int x, int y) {
if (p->kids[0]) {
drawLines(p->kids[0], x + p->x.scratch, y + Y_SCALE);
drawLine(x + p->x.scratch, y, x + p->x.scratch + p->kids[0]->x.scratch, y + Y_SCALE);
}
if (p->kids[1]) {
drawLines(p->kids[1], x + p->x.scratch, y + Y_SCALE);
drawLine(x + p->x.scratch, y, x + p->x.scratch + p->kids[1]->x.scratch, y + Y_SCALE);
}
}
static void drawNodes(Node p, int x, int y) {
drawNode(p, x + p->x.scratch, y);
if (p->kids[0]) {
drawNodes(p->kids[0], x + p->x.scratch, y + Y_SCALE);
}
if (p->kids[1]) {
drawNodes(p->kids[1], x + p->x.scratch, y + Y_SCALE);
}
}
static int doTree(Node p, int y) {
Shape shape = treeWalk(p);
int i, centre;
int left = 0;
int right = 0;
p->x.scratch = 0;
for (i = 0; i < shape->length; i++) {
left = max(left, shape->items[i].left);
right = max(right, shape->items[i].right);
}
centre = (left - right)/2;
drawLines(p, centre, y);
drawNodes(p, centre, y);
return y + shape->length * Y_SCALE + Y_SPACING;
}
static int y = 50;
static void treeemit(Node forest) {
Node p;
for (p = forest; p; p = p->link) {
if (generic(p->op) != NOOP) {
y = doTree(p, y);
}
}
}
#define char_metrics { 1, 1, 0 }
#define short_metrics { 2, 2, 0 }
#define int_metrics { 4, 4, 0 }
#define long_metrics { 4, 4, 0 }
#define long_long_metrics { 4, 4, 0 }
#define float_metrics { 4, 4, 0 }
#define double_metrics { 4, 4, 0 }
#define long_double_metrics { 4, 4, 0 }
#define word_metrics { 4, 4, 0 }
#define struct_metrics { 0, 4, 0 }
Interface svgIR = {
char_metrics,
short_metrics,
int_metrics,
long_metrics,
long_long_metrics,
float_metrics,
double_metrics,
long_double_metrics,
word_metrics,
struct_metrics,
0,
0, /* mulops_calls */
0, /* wants_callb */
0, /* wants_argb */
1, /* left_to_right */
0, /* wants_dag */
0, /* unsigned_char */
address,
blockbeg,
blockend,
defaddress,
defconst,
defstring,
defsymbol,
treeemit,
export,
function,
stackgen,
global,
import,
local,
progbeg,
progend,
segment,
space,
0, 0, 0, stabinit, stabline, stabsym, 0,
swtch,
{
1, /* max_unaligned_load */
4,
recalcNode,
makeTemp,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
{
0, // sub
0, // lsh
0, // rsh
0, // mod
0, // div
0, // lt
0, // le
0, // gt
0 // ge
}
}
};