/** 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"); backendflags(argc, argv); } static void progend(void) { 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 } } };