2005-08-26 17:39:27 +00:00
|
|
|
#include "c.h"
|
|
|
|
|
|
|
|
|
|
|
|
#define iscall(op) (generic(op) == CALL \
|
2005-10-04 01:21:34 +00:00
|
|
|
|| (IR->mulops_calls \
|
2005-08-26 17:39:27 +00:00
|
|
|
&& (generic(op)==DIV||generic(op)==MOD||generic(op)==MUL) \
|
2005-10-04 01:21:34 +00:00
|
|
|
&& ( optype(op)==U || optype(op)==I)))
|
2005-08-26 17:39:27 +00:00
|
|
|
static Node forest;
|
|
|
|
static struct dag {
|
|
|
|
struct node node;
|
|
|
|
struct dag *hlink;
|
|
|
|
} *buckets[16];
|
|
|
|
int nodecount;
|
|
|
|
static Tree firstarg;
|
|
|
|
int assignargs = 1;
|
|
|
|
int prunetemps = -1;
|
|
|
|
static Node *tail;
|
|
|
|
|
|
|
|
static int depth = 0;
|
|
|
|
static Node replace(Node);
|
|
|
|
static Node prune(Node);
|
|
|
|
static Node asgnnode(Symbol, Node);
|
|
|
|
static struct dag *dagnode(int, Node, Node, Symbol);
|
|
|
|
static Symbol equated(Symbol);
|
|
|
|
static void fixup(Node);
|
|
|
|
static void labelnode(int);
|
|
|
|
static void list(Node);
|
|
|
|
static void kill(Symbol);
|
|
|
|
static Node node(int, Node, Node, Symbol);
|
|
|
|
static void printdag1(Node, int, int);
|
|
|
|
static void printnode(Node, int, int);
|
|
|
|
static void reset(void);
|
|
|
|
static Node tmpnode(Node);
|
|
|
|
static void typestab(Symbol, void *);
|
|
|
|
static Node undag(Node);
|
|
|
|
static Node visit(Node, int);
|
|
|
|
static void unlist(void);
|
|
|
|
void walk(Tree tp, int tlab, int flab) {
|
|
|
|
listnodes(tp, tlab, flab);
|
|
|
|
if (forest) {
|
|
|
|
Node list = forest->link;
|
|
|
|
forest->link = NULL;
|
|
|
|
if (!IR->wants_dag)
|
|
|
|
list = undag(list);
|
|
|
|
code(Gen)->u.forest = list;
|
|
|
|
forest = NULL;
|
|
|
|
}
|
|
|
|
reset();
|
|
|
|
deallocate(STMT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Node node(int op, Node l, Node r, Symbol sym) {
|
|
|
|
int i;
|
|
|
|
struct dag *p;
|
|
|
|
|
|
|
|
i = (opindex(op)^((unsigned long)sym>>2))&(NELEMS(buckets)-1);
|
|
|
|
for (p = buckets[i]; p; p = p->hlink)
|
|
|
|
if (p->node.op == op && p->node.syms[0] == sym
|
|
|
|
&& p->node.kids[0] == l && p->node.kids[1] == r)
|
|
|
|
return &p->node;
|
|
|
|
p = dagnode(op, l, r, sym);
|
|
|
|
p->hlink = buckets[i];
|
|
|
|
buckets[i] = p;
|
|
|
|
++nodecount;
|
|
|
|
return &p->node;
|
|
|
|
}
|
|
|
|
static struct dag *dagnode(int op, Node l, Node r, Symbol sym) {
|
|
|
|
struct dag *p;
|
|
|
|
|
|
|
|
NEW0(p, FUNC);
|
|
|
|
p->node.op = op;
|
|
|
|
if ((p->node.kids[0] = l) != NULL)
|
|
|
|
++l->count;
|
|
|
|
if ((p->node.kids[1] = r) != NULL)
|
|
|
|
++r->count;
|
|
|
|
p->node.syms[0] = sym;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
Node newnode(int op, Node l, Node r, Symbol sym) {
|
|
|
|
return &dagnode(op, l, r, sym)->node;
|
|
|
|
}
|
|
|
|
static void kill(Symbol p) {
|
|
|
|
int i;
|
|
|
|
struct dag **q;
|
|
|
|
|
|
|
|
for (i = 0; i < NELEMS(buckets); i++)
|
|
|
|
for (q = &buckets[i]; *q; )
|
|
|
|
if (generic((*q)->node.op) == INDIR &&
|
|
|
|
(!isaddrop((*q)->node.kids[0]->op)
|
|
|
|
|| (*q)->node.kids[0]->syms[0] == p)) {
|
|
|
|
*q = (*q)->hlink;
|
|
|
|
--nodecount;
|
|
|
|
} else
|
|
|
|
q = &(*q)->hlink;
|
|
|
|
}
|
|
|
|
static void reset(void) {
|
|
|
|
if (nodecount > 0)
|
|
|
|
memset(buckets, 0, sizeof buckets);
|
|
|
|
nodecount = 0;
|
|
|
|
}
|
|
|
|
Node listnodes(Tree tp, int tlab, int flab) {
|
|
|
|
Node p = NULL, l, r;
|
|
|
|
int op;
|
|
|
|
|
2005-10-04 01:21:34 +00:00
|
|
|
assert(tlab || flab || (tlab == 0 && flab == 0));
|
2005-08-26 17:39:27 +00:00
|
|
|
if (tp == NULL)
|
|
|
|
return NULL;
|
|
|
|
if (tp->node)
|
|
|
|
return tp->node;
|
|
|
|
op = tp->op + sizeop(tp->type->size);
|
|
|
|
switch (generic(tp->op)) {
|
|
|
|
case AND: { if (depth++ == 0) reset();
|
|
|
|
if (flab) {
|
|
|
|
listnodes(tp->kids[0], 0, flab);
|
|
|
|
listnodes(tp->kids[1], 0, flab);
|
|
|
|
} else {
|
|
|
|
listnodes(tp->kids[0], 0, flab = genlabel(1));
|
|
|
|
listnodes(tp->kids[1], tlab, 0);
|
|
|
|
labelnode(flab);
|
|
|
|
}
|
|
|
|
depth--; } break;
|
|
|
|
case OR: { if (depth++ == 0)
|
|
|
|
reset();
|
|
|
|
if (tlab) {
|
|
|
|
listnodes(tp->kids[0], tlab, 0);
|
|
|
|
listnodes(tp->kids[1], tlab, 0);
|
|
|
|
} else {
|
|
|
|
tlab = genlabel(1);
|
|
|
|
listnodes(tp->kids[0], tlab, 0);
|
|
|
|
listnodes(tp->kids[1], 0, flab);
|
|
|
|
labelnode(tlab);
|
|
|
|
}
|
|
|
|
depth--;
|
|
|
|
} break;
|
|
|
|
case NOT: { return listnodes(tp->kids[0], flab, tlab); }
|
|
|
|
case COND: { Tree q = tp->kids[1];
|
|
|
|
assert(tlab == 0 && flab == 0);
|
|
|
|
if (tp->u.sym)
|
|
|
|
addlocal(tp->u.sym);
|
|
|
|
flab = genlabel(2);
|
|
|
|
listnodes(tp->kids[0], 0, flab);
|
|
|
|
assert(q && q->op == RIGHT);
|
|
|
|
reset();
|
|
|
|
listnodes(q->kids[0], 0, 0);
|
|
|
|
if (forest->op == LABEL+V) {
|
|
|
|
equatelab(forest->syms[0], findlabel(flab + 1));
|
|
|
|
unlist();
|
|
|
|
}
|
|
|
|
list(jump(flab + 1));
|
|
|
|
labelnode(flab);
|
|
|
|
listnodes(q->kids[1], 0, 0);
|
|
|
|
if (forest->op == LABEL+V) {
|
|
|
|
equatelab(forest->syms[0], findlabel(flab + 1));
|
|
|
|
unlist();
|
|
|
|
}
|
|
|
|
labelnode(flab + 1);
|
|
|
|
|
|
|
|
if (tp->u.sym)
|
|
|
|
p = listnodes(idtree(tp->u.sym), 0, 0); } break;
|
|
|
|
case CNST: { Type ty = unqual(tp->type);
|
|
|
|
assert(ty->u.sym);
|
|
|
|
if (tlab || flab) {
|
|
|
|
assert(ty == inttype);
|
|
|
|
if (tlab && tp->u.v.i != 0)
|
|
|
|
list(jump(tlab));
|
|
|
|
else if (flab && tp->u.v.i == 0)
|
|
|
|
list(jump(flab));
|
|
|
|
}
|
|
|
|
else if (ty->u.sym->addressed)
|
|
|
|
p = listnodes(cvtconst(tp), 0, 0);
|
|
|
|
else
|
|
|
|
p = node(op, NULL, NULL, constant(ty, tp->u.v)); } break;
|
|
|
|
case RIGHT: { if ( tp->kids[0] && tp->kids[1]
|
|
|
|
&& generic(tp->kids[1]->op) == ASGN
|
2005-10-04 01:21:34 +00:00
|
|
|
&& ((generic(tp->kids[0]->op) == INDIR
|
|
|
|
&& tp->kids[0]->kids[0] == tp->kids[1]->kids[0])
|
2005-08-26 17:39:27 +00:00
|
|
|
|| (tp->kids[0]->op == FIELD
|
|
|
|
&& tp->kids[0] == tp->kids[1]->kids[0]))) {
|
|
|
|
assert(tlab == 0 && flab == 0);
|
|
|
|
if (generic(tp->kids[0]->op) == INDIR) {
|
|
|
|
p = listnodes(tp->kids[0], 0, 0);
|
|
|
|
list(p);
|
|
|
|
listnodes(tp->kids[1], 0, 0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
assert(generic(tp->kids[0]->kids[0]->op) == INDIR);
|
|
|
|
list(listnodes(tp->kids[0]->kids[0], 0, 0));
|
|
|
|
p = listnodes(tp->kids[0], 0, 0);
|
|
|
|
listnodes(tp->kids[1], 0, 0);
|
|
|
|
}
|
|
|
|
} else if (tp->kids[1]) {
|
|
|
|
listnodes(tp->kids[0], 0, 0);
|
|
|
|
p = listnodes(tp->kids[1], tlab, flab);
|
|
|
|
} else
|
|
|
|
p = listnodes(tp->kids[0], tlab, flab); } break;
|
|
|
|
case JUMP: { assert(tlab == 0 && flab == 0);
|
|
|
|
assert(tp->u.sym == 0);
|
|
|
|
assert(tp->kids[0]);
|
|
|
|
l = listnodes(tp->kids[0], 0, 0);
|
|
|
|
list(newnode(JUMP+V, l, NULL, NULL));
|
|
|
|
reset(); } break;
|
|
|
|
case CALL: { Tree save = firstarg;
|
|
|
|
firstarg = NULL;
|
|
|
|
assert(tlab == 0 && flab == 0);
|
|
|
|
if (tp->op == CALL+B && !IR->wants_callb) {
|
|
|
|
Tree arg0 = tree(ARG+P, tp->kids[1]->type,
|
|
|
|
tp->kids[1], NULL);
|
|
|
|
if (IR->left_to_right)
|
|
|
|
firstarg = arg0;
|
|
|
|
l = listnodes(tp->kids[0], 0, 0);
|
|
|
|
if (!IR->left_to_right || firstarg) {
|
|
|
|
firstarg = NULL;
|
|
|
|
listnodes(arg0, 0, 0);
|
|
|
|
}
|
|
|
|
p = newnode(CALL+V, l, NULL, NULL);
|
|
|
|
} else {
|
|
|
|
l = listnodes(tp->kids[0], 0, 0);
|
|
|
|
r = listnodes(tp->kids[1], 0, 0);
|
|
|
|
p = newnode(tp->op == CALL+B ? tp->op : op, l, r, NULL);
|
|
|
|
}
|
|
|
|
NEW0(p->syms[0], FUNC);
|
|
|
|
assert(isptr(tp->kids[0]->type));
|
|
|
|
assert(isfunc(tp->kids[0]->type->type));
|
|
|
|
p->syms[0]->type = tp->kids[0]->type->type;
|
|
|
|
list(p);
|
|
|
|
reset();
|
|
|
|
cfunc->u.f.ncalls++;
|
|
|
|
firstarg = save;
|
|
|
|
} break;
|
|
|
|
case ARG: { assert(tlab == 0 && flab == 0);
|
|
|
|
if (IR->left_to_right)
|
|
|
|
listnodes(tp->kids[1], 0, 0);
|
|
|
|
if (firstarg) {
|
|
|
|
Tree arg = firstarg;
|
|
|
|
firstarg = NULL;
|
|
|
|
listnodes(arg, 0, 0);
|
|
|
|
}
|
|
|
|
l = listnodes(tp->kids[0], 0, 0);
|
|
|
|
list(newnode(tp->op == ARG+B ? tp->op : op, l, NULL, NULL));
|
|
|
|
forest->syms[0] = intconst(tp->type->size);
|
|
|
|
forest->syms[1] = intconst(tp->type->align);
|
|
|
|
if (!IR->left_to_right)
|
|
|
|
listnodes(tp->kids[1], 0, 0); } break;
|
|
|
|
case EQ: case NE: case GT: case GE: case LE:
|
|
|
|
case LT: { assert(tp->u.sym == 0);
|
|
|
|
assert(errcnt || tlab || flab);
|
|
|
|
l = listnodes(tp->kids[0], 0, 0);
|
|
|
|
r = listnodes(tp->kids[1], 0, 0);
|
|
|
|
assert(errcnt || opkind(l->op) == opkind(r->op));
|
|
|
|
assert(errcnt || optype(op) == optype(l->op));
|
|
|
|
if (tlab)
|
|
|
|
assert(flab == 0),
|
|
|
|
list(newnode(generic(tp->op) + opkind(l->op), l, r, findlabel(tlab)));
|
|
|
|
else if (flab) {
|
|
|
|
switch (generic(tp->op)) {
|
|
|
|
case EQ: op = NE; break;
|
|
|
|
case NE: op = EQ; break;
|
|
|
|
case GT: op = LE; break;
|
|
|
|
case LT: op = GE; break;
|
|
|
|
case GE: op = LT; break;
|
|
|
|
case LE: op = GT; break;
|
|
|
|
default: assert(0);
|
|
|
|
}
|
|
|
|
list(newnode(op + opkind(l->op), l, r, findlabel(flab)));
|
|
|
|
}
|
|
|
|
if (forest && forest->syms[0])
|
|
|
|
forest->syms[0]->ref++; } break;
|
|
|
|
case ASGN: { assert(tlab == 0 && flab == 0);
|
|
|
|
if (tp->kids[0]->op == FIELD) {
|
|
|
|
Tree x = tp->kids[0]->kids[0];
|
|
|
|
Field f = tp->kids[0]->u.field;
|
|
|
|
assert(generic(x->op) == INDIR);
|
|
|
|
reset();
|
|
|
|
l = listnodes(lvalue(x), 0, 0);
|
|
|
|
if (fieldsize(f) < 8*f->type->size) {
|
|
|
|
unsigned int fmask = fieldmask(f);
|
|
|
|
unsigned int mask = fmask<<fieldright(f);
|
|
|
|
Tree q = tp->kids[1];
|
2005-10-04 01:21:34 +00:00
|
|
|
if ((q->op == CNST+I && q->u.v.i == 0)
|
|
|
|
|| (q->op == CNST+U && q->u.v.u == 0))
|
2005-08-26 17:39:27 +00:00
|
|
|
q = bittree(BAND, x, cnsttree(unsignedtype, (unsigned long)~mask));
|
2005-10-04 01:21:34 +00:00
|
|
|
else if ((q->op == CNST+I && (q->u.v.i&fmask) == fmask)
|
|
|
|
|| (q->op == CNST+U && (q->u.v.u&fmask) == fmask))
|
2005-08-26 17:39:27 +00:00
|
|
|
q = bittree(BOR, x, cnsttree(unsignedtype, (unsigned long)mask));
|
|
|
|
else {
|
|
|
|
listnodes(q, 0, 0);
|
|
|
|
q = bittree(BOR,
|
|
|
|
bittree(BAND, rvalue(lvalue(x)),
|
|
|
|
cnsttree(unsignedtype, (unsigned long)~mask)),
|
|
|
|
bittree(BAND, shtree(LSH, cast(q, unsignedtype),
|
|
|
|
cnsttree(unsignedtype, (unsigned long)fieldright(f))),
|
|
|
|
cnsttree(unsignedtype, (unsigned long)mask)));
|
|
|
|
}
|
|
|
|
r = listnodes(q, 0, 0);
|
|
|
|
op = ASGN + ttob(q->type);
|
|
|
|
} else {
|
|
|
|
r = listnodes(tp->kids[1], 0, 0);
|
|
|
|
op = ASGN + ttob(tp->kids[1]->type);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
l = listnodes(tp->kids[0], 0, 0);
|
|
|
|
r = listnodes(tp->kids[1], 0, 0);
|
|
|
|
}
|
|
|
|
list(newnode(tp->op == ASGN+B ? tp->op : op, l, r, NULL));
|
|
|
|
forest->syms[0] = intconst(tp->kids[1]->type->size);
|
|
|
|
forest->syms[1] = intconst(tp->kids[1]->type->align);
|
|
|
|
if (isaddrop(tp->kids[0]->op)
|
|
|
|
&& !tp->kids[0]->u.sym->computed)
|
|
|
|
kill(tp->kids[0]->u.sym);
|
|
|
|
else
|
|
|
|
reset();
|
|
|
|
p = listnodes(tp->kids[1], 0, 0); } break;
|
|
|
|
case BOR: case BAND: case BXOR:
|
|
|
|
case ADD: case SUB: case RSH:
|
|
|
|
case LSH: { assert(tlab == 0 && flab == 0);
|
|
|
|
l = listnodes(tp->kids[0], 0, 0);
|
|
|
|
r = listnodes(tp->kids[1], 0, 0);
|
|
|
|
p = node(op, l, r, NULL); } break;
|
|
|
|
case DIV: case MUL:
|
|
|
|
case MOD: { assert(tlab == 0 && flab == 0);
|
|
|
|
l = listnodes(tp->kids[0], 0, 0);
|
|
|
|
r = listnodes(tp->kids[1], 0, 0);
|
|
|
|
p = node(op, l, r, NULL);
|
|
|
|
if (IR->mulops_calls && isint(tp->type)) {
|
|
|
|
list(p);
|
|
|
|
cfunc->u.f.ncalls++;
|
|
|
|
} } break;
|
|
|
|
case RET: { assert(tlab == 0 && flab == 0);
|
|
|
|
l = listnodes(tp->kids[0], 0, 0);
|
|
|
|
list(newnode(op, l, NULL, NULL)); } break;
|
|
|
|
case CVF: case CVI: case CVP:
|
|
|
|
case CVU: { assert(tlab == 0 && flab == 0);
|
|
|
|
assert(optype(tp->kids[0]->op) != optype(tp->op) || tp->kids[0]->type->size != tp->type->size);
|
|
|
|
l = listnodes(tp->kids[0], 0, 0);
|
|
|
|
p = node(op, l, NULL, intconst(tp->kids[0]->type->size));
|
|
|
|
} break;
|
|
|
|
case BCOM:
|
|
|
|
case NEG: { assert(tlab == 0 && flab == 0);
|
|
|
|
l = listnodes(tp->kids[0], 0, 0);
|
|
|
|
p = node(op, l, NULL, NULL); } break;
|
|
|
|
case INDIR: { Type ty = tp->kids[0]->type;
|
|
|
|
assert(tlab == 0 && flab == 0);
|
|
|
|
l = listnodes(tp->kids[0], 0, 0);
|
|
|
|
if (isptr(ty))
|
|
|
|
ty = unqual(ty)->type;
|
|
|
|
if (isvolatile(ty)
|
|
|
|
|| (isstruct(ty) && unqual(ty)->u.sym->u.s.vfields))
|
|
|
|
p = newnode(tp->op == INDIR+B ? tp->op : op, l, NULL, NULL);
|
|
|
|
else
|
|
|
|
p = node(tp->op == INDIR+B ? tp->op : op, l, NULL, NULL); } break;
|
|
|
|
case FIELD: { Tree q = tp->kids[0];
|
|
|
|
if (tp->type == inttype) {
|
|
|
|
long n = fieldleft(tp->u.field);
|
|
|
|
q = shtree(RSH,
|
|
|
|
shtree(LSH, q, cnsttree(inttype, n)),
|
|
|
|
cnsttree(inttype, n + fieldright(tp->u.field)));
|
|
|
|
} else if (fieldsize(tp->u.field) < 8*tp->u.field->type->size)
|
|
|
|
q = bittree(BAND,
|
|
|
|
shtree(RSH, q, cnsttree(inttype, (long)fieldright(tp->u.field))),
|
|
|
|
cnsttree(unsignedtype, (unsigned long)fieldmask(tp->u.field)));
|
|
|
|
assert(tlab == 0 && flab == 0);
|
|
|
|
p = listnodes(q, 0, 0); } break;
|
|
|
|
case ADDRG:
|
|
|
|
case ADDRF: { assert(tlab == 0 && flab == 0);
|
|
|
|
p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym);
|
|
|
|
} break;
|
|
|
|
case ADDRL: { assert(tlab == 0 && flab == 0);
|
|
|
|
if (tp->u.sym->temporary)
|
|
|
|
addlocal(tp->u.sym);
|
|
|
|
p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym); } break;
|
|
|
|
default:assert(0);
|
|
|
|
}
|
|
|
|
tp->node = p;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
static void list(Node p) {
|
|
|
|
if (p && p->link == NULL) {
|
|
|
|
if (forest) {
|
|
|
|
p->link = forest->link;
|
|
|
|
forest->link = p;
|
|
|
|
} else
|
|
|
|
p->link = p;
|
|
|
|
forest = p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void labelnode(int lab) {
|
|
|
|
assert(lab);
|
|
|
|
if (forest && forest->op == LABEL+V)
|
|
|
|
equatelab(findlabel(lab), forest->syms[0]);
|
|
|
|
else
|
|
|
|
list(newnode(LABEL+V, NULL, NULL, findlabel(lab)));
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
static void unlist(void) {
|
|
|
|
Node p;
|
|
|
|
|
|
|
|
assert(forest);
|
|
|
|
assert(forest != forest->link);
|
|
|
|
p = forest->link;
|
|
|
|
while (p->link != forest)
|
|
|
|
p = p->link;
|
|
|
|
p->link = forest->link;
|
|
|
|
forest = p;
|
|
|
|
}
|
|
|
|
Tree cvtconst(Tree p) {
|
|
|
|
Symbol q = constant(p->type, p->u.v);
|
|
|
|
Tree e;
|
|
|
|
|
|
|
|
if (q->u.c.loc == NULL)
|
|
|
|
q->u.c.loc = genident(STATIC, p->type, GLOBAL);
|
|
|
|
if (isarray(p->type)) {
|
|
|
|
e = simplify(ADDRG, atop(p->type), NULL, NULL);
|
|
|
|
e->u.sym = q->u.c.loc;
|
|
|
|
} else
|
|
|
|
e = idtree(q->u.c.loc);
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
void gencode(Symbol caller[], Symbol callee[]) {
|
|
|
|
Code cp;
|
|
|
|
Coordinate save;
|
|
|
|
|
|
|
|
if (prunetemps == -1)
|
|
|
|
prunetemps = !IR->wants_dag;
|
|
|
|
save = src;
|
|
|
|
if (assignargs) {
|
|
|
|
int i;
|
|
|
|
Symbol p, q;
|
|
|
|
cp = codehead.next->next;
|
|
|
|
codelist = codehead.next;
|
|
|
|
for (i = 0; (p = callee[i]) != NULL
|
|
|
|
&& (q = caller[i]) != NULL; i++)
|
|
|
|
if (p->sclass != q->sclass || p->type != q->type)
|
|
|
|
walk(asgn(p, idtree(q)), 0, 0);
|
|
|
|
codelist->next = cp;
|
|
|
|
cp->prev = codelist;
|
|
|
|
}
|
|
|
|
if (glevel && IR->stabsym) {
|
|
|
|
int i;
|
|
|
|
Symbol p, q;
|
|
|
|
for (i = 0; (p = callee[i]) != NULL
|
|
|
|
&& (q = caller[i]) != NULL; i++) {
|
|
|
|
(*IR->stabsym)(p);
|
|
|
|
if (p->sclass != q->sclass || p->type != q->type)
|
|
|
|
(*IR->stabsym)(q);
|
|
|
|
}
|
|
|
|
swtoseg(CODE);
|
|
|
|
}
|
|
|
|
cp = codehead.next;
|
|
|
|
for ( ; errcnt <= 0 && cp; cp = cp->next)
|
|
|
|
switch (cp->kind) {
|
|
|
|
case Address: (*IR->address)(cp->u.addr.sym, cp->u.addr.base,
|
|
|
|
cp->u.addr.offset); break;
|
|
|
|
case Blockbeg: {
|
|
|
|
Symbol *p = cp->u.block.locals;
|
|
|
|
(*IR->blockbeg)(&cp->u.block.x);
|
|
|
|
for ( ; *p; p++)
|
|
|
|
if ((*p)->ref != 0.0)
|
|
|
|
(*IR->local)(*p);
|
|
|
|
else if (glevel) (*IR->local)(*p);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Blockend: (*IR->blockend)(&cp->u.begin->u.block.x); break;
|
|
|
|
case Defpoint: src = cp->u.point.src; break;
|
|
|
|
case Gen: case Jump:
|
|
|
|
case Label: if (prunetemps)
|
|
|
|
cp->u.forest = prune(cp->u.forest);
|
|
|
|
fixup(cp->u.forest);
|
|
|
|
cp->u.forest = (*IR->gen)(cp->u.forest); break;
|
|
|
|
case Local: (*IR->local)(cp->u.var); break;
|
|
|
|
case Switch: break;
|
|
|
|
default: assert(0);
|
|
|
|
}
|
|
|
|
src = save;
|
|
|
|
}
|
|
|
|
static void fixup(Node p) {
|
|
|
|
for ( ; p; p = p->link)
|
|
|
|
switch (generic(p->op)) {
|
|
|
|
case JUMP:
|
|
|
|
if (specific(p->kids[0]->op) == ADDRG+P)
|
|
|
|
p->kids[0]->syms[0] =
|
|
|
|
equated(p->kids[0]->syms[0]);
|
|
|
|
break;
|
|
|
|
case LABEL: assert(p->syms[0] == equated(p->syms[0])); break;
|
|
|
|
case EQ: case GE: case GT: case LE: case LT: case NE:
|
|
|
|
assert(p->syms[0]);
|
|
|
|
p->syms[0] = equated(p->syms[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static Symbol equated(Symbol p) {
|
|
|
|
{ Symbol q; for (q = p->u.l.equatedto; q; q = q->u.l.equatedto) assert(p != q); }
|
|
|
|
while (p->u.l.equatedto)
|
|
|
|
p = p->u.l.equatedto;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
void emitcode(void) {
|
|
|
|
Code cp;
|
|
|
|
Coordinate save;
|
|
|
|
|
|
|
|
save = src;
|
|
|
|
cp = codehead.next;
|
|
|
|
for ( ; errcnt <= 0 && cp; cp = cp->next)
|
|
|
|
switch (cp->kind) {
|
|
|
|
case Address: break;
|
|
|
|
case Blockbeg: if (glevel && IR->stabblock) {
|
|
|
|
(*IR->stabblock)('{', cp->u.block.level - LOCAL, cp->u.block.locals);
|
|
|
|
swtoseg(CODE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Blockend: if (glevel && IR->stabblock) {
|
|
|
|
Code bp = cp->u.begin;
|
|
|
|
foreach(bp->u.block.identifiers, bp->u.block.level, typestab, NULL);
|
|
|
|
foreach(bp->u.block.types, bp->u.block.level, typestab, NULL);
|
|
|
|
(*IR->stabblock)('}', bp->u.block.level - LOCAL, bp->u.block.locals);
|
|
|
|
swtoseg(CODE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Defpoint: src = cp->u.point.src;
|
|
|
|
if (glevel > 0 && IR->stabline) {
|
|
|
|
(*IR->stabline)(&cp->u.point.src); swtoseg(CODE); } break;
|
|
|
|
case Gen: case Jump:
|
|
|
|
case Label: if (cp->u.forest)
|
|
|
|
(*IR->emit)(cp->u.forest); break;
|
|
|
|
case Local: if (glevel && IR->stabsym) {
|
|
|
|
(*IR->stabsym)(cp->u.var);
|
|
|
|
swtoseg(CODE);
|
|
|
|
} break;
|
|
|
|
case Switch: { int i;
|
|
|
|
defglobal(cp->u.swtch.table, LIT);
|
|
|
|
(*IR->defaddress)(equated(cp->u.swtch.labels[0]));
|
|
|
|
for (i = 1; i < cp->u.swtch.size; i++) {
|
|
|
|
long k = cp->u.swtch.values[i-1];
|
|
|
|
while (++k < cp->u.swtch.values[i])
|
|
|
|
assert(k < LONG_MAX),
|
|
|
|
(*IR->defaddress)(equated(cp->u.swtch.deflab));
|
|
|
|
(*IR->defaddress)(equated(cp->u.swtch.labels[i]));
|
|
|
|
}
|
|
|
|
swtoseg(CODE);
|
|
|
|
} break;
|
|
|
|
default: assert(0);
|
|
|
|
}
|
|
|
|
src = save;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Node undag(Node forest) {
|
|
|
|
Node p;
|
|
|
|
|
|
|
|
tail = &forest;
|
|
|
|
for (p = forest; p; p = p->link)
|
|
|
|
if (generic(p->op) == INDIR) {
|
|
|
|
assert(p->count >= 1);
|
|
|
|
visit(p, 1);
|
|
|
|
if (p->syms[2]) {
|
|
|
|
assert(p->syms[2]->u.t.cse);
|
|
|
|
p->syms[2]->u.t.cse = NULL;
|
|
|
|
addlocal(p->syms[2]);
|
|
|
|
}
|
|
|
|
} else if (iscall(p->op) && p->count >= 1)
|
|
|
|
visit(p, 1);
|
|
|
|
else {
|
|
|
|
assert(p->count == 0),
|
|
|
|
visit(p, 1);
|
|
|
|
*tail = p;
|
|
|
|
tail = &p->link;
|
|
|
|
}
|
|
|
|
*tail = NULL;
|
|
|
|
return forest;
|
|
|
|
}
|
|
|
|
static Node replace(Node p) {
|
|
|
|
if (p && ( generic(p->op) == INDIR
|
|
|
|
&& generic(p->kids[0]->op) == ADDRL
|
|
|
|
&& p->kids[0]->syms[0]->temporary
|
|
|
|
&& p->kids[0]->syms[0]->u.t.replace)) {
|
|
|
|
p = p->kids[0]->syms[0]->u.t.cse;
|
|
|
|
if (generic(p->op) == INDIR && isaddrop(p->kids[0]->op))
|
|
|
|
p = newnode(p->op, newnode(p->kids[0]->op, NULL, NULL,
|
|
|
|
p->kids[0]->syms[0]), NULL, NULL);
|
|
|
|
else if (generic(p->op) == ADDRG)
|
|
|
|
p = newnode(p->op, NULL, NULL, p->syms[0]);
|
|
|
|
else
|
|
|
|
assert(0);
|
|
|
|
p->count = 1;
|
|
|
|
} else if (p) {
|
|
|
|
p->kids[0] = replace(p->kids[0]);
|
|
|
|
p->kids[1] = replace(p->kids[1]);
|
|
|
|
}
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
static Node prune(Node forest) {
|
|
|
|
Node p, *tail = &forest;
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
for (p = forest; p; p = p->link) {
|
|
|
|
if (count > 0) {
|
|
|
|
p->kids[0] = replace(p->kids[0]);
|
|
|
|
p->kids[1] = replace(p->kids[1]);
|
|
|
|
}
|
|
|
|
if (( generic(p->op) == ASGN
|
|
|
|
&& generic(p->kids[0]->op) == ADDRL
|
|
|
|
&& p->kids[0]->syms[0]->temporary
|
|
|
|
&& p->kids[0]->syms[0]->u.t.cse == p->kids[1])) {
|
|
|
|
Symbol tmp = p->kids[0]->syms[0];
|
|
|
|
if (!tmp->defined)
|
|
|
|
(*IR->local)(tmp);
|
|
|
|
tmp->defined = 1;
|
|
|
|
if (( generic(p->kids[1]->op) == INDIR
|
|
|
|
&& isaddrop(p->kids[1]->kids[0]->op)
|
|
|
|
&& p->kids[1]->kids[0]->syms[0]->sclass == REGISTER)
|
|
|
|
|| (( generic(p->kids[1]->op) == INDIR
|
|
|
|
&& isaddrop(p->kids[1]->kids[0]->op)) && tmp->sclass == AUTO)
|
|
|
|
|| (generic(p->kids[1]->op) == ADDRG && tmp->sclass == AUTO)) {
|
|
|
|
tmp->u.t.replace = 1;
|
|
|
|
count++;
|
|
|
|
continue; /* and omit the assignment */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* keep the assignment and other roots */
|
|
|
|
*tail = p;
|
|
|
|
tail = &(*tail)->link;
|
|
|
|
}
|
|
|
|
assert(*tail == NULL);
|
|
|
|
return forest;
|
|
|
|
}
|
|
|
|
static Node visit(Node p, int listed) {
|
2005-10-04 01:21:34 +00:00
|
|
|
if (p) {
|
2005-08-26 17:39:27 +00:00
|
|
|
if (p->syms[2])
|
|
|
|
p = tmpnode(p);
|
2005-10-04 01:21:34 +00:00
|
|
|
else if ((p->count <= 1 && !iscall(p->op))
|
|
|
|
|| (p->count == 0 && iscall(p->op))) {
|
2005-08-26 17:39:27 +00:00
|
|
|
p->kids[0] = visit(p->kids[0], 0);
|
|
|
|
p->kids[1] = visit(p->kids[1], 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (specific(p->op) == ADDRL+P || specific(p->op) == ADDRF+P) {
|
|
|
|
assert(!listed);
|
|
|
|
p = newnode(p->op, NULL, NULL, p->syms[0]);
|
|
|
|
p->count = 1;
|
|
|
|
}
|
|
|
|
else if (p->op == INDIR+B) {
|
|
|
|
p = newnode(p->op, p->kids[0], NULL, NULL);
|
|
|
|
p->count = 1;
|
|
|
|
p->kids[0] = visit(p->kids[0], 0);
|
|
|
|
p->kids[1] = visit(p->kids[1], 0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
p->kids[0] = visit(p->kids[0], 0);
|
|
|
|
p->kids[1] = visit(p->kids[1], 0);
|
|
|
|
p->syms[2] = temporary(REGISTER, btot(p->op, opsize(p->op)));
|
|
|
|
assert(!p->syms[2]->defined);
|
|
|
|
p->syms[2]->ref = 1;
|
|
|
|
p->syms[2]->u.t.cse = p;
|
|
|
|
|
|
|
|
*tail = asgnnode(p->syms[2], p);
|
|
|
|
tail = &(*tail)->link;
|
|
|
|
if (!listed)
|
|
|
|
p = tmpnode(p);
|
|
|
|
};
|
2005-10-04 01:21:34 +00:00
|
|
|
}
|
2005-08-26 17:39:27 +00:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
static Node tmpnode(Node p) {
|
|
|
|
Symbol tmp = p->syms[2];
|
|
|
|
|
|
|
|
assert(tmp);
|
|
|
|
if (--p->count == 0)
|
|
|
|
p->syms[2] = NULL;
|
|
|
|
p = newnode(INDIR + ttob(tmp->type),
|
|
|
|
newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), NULL, NULL);
|
|
|
|
p->count = 1;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
static Node asgnnode(Symbol tmp, Node p) {
|
|
|
|
p = newnode(ASGN + ttob(tmp->type),
|
|
|
|
newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), p, NULL);
|
|
|
|
p->syms[0] = intconst(tmp->type->size);
|
|
|
|
p->syms[1] = intconst(tmp->type->align);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
/* printdag - print dag p on fd, or the node list if p == 0 */
|
|
|
|
void printdag(Node p, int fd) {
|
|
|
|
FILE *f = fd == 1 ? stdout : stderr;
|
|
|
|
|
|
|
|
printed(0);
|
|
|
|
if (p == 0) {
|
|
|
|
if ((p = forest) != NULL)
|
|
|
|
do {
|
|
|
|
p = p->link;
|
|
|
|
printdag1(p, fd, 0);
|
|
|
|
} while (p != forest);
|
|
|
|
} else if (*printed(nodeid((Tree)p)))
|
|
|
|
fprint(f, "node'%d printed above\n", nodeid((Tree)p));
|
|
|
|
else
|
|
|
|
printdag1(p, fd, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* printdag1 - recursively print dag p */
|
|
|
|
static void printdag1(Node p, int fd, int lev) {
|
|
|
|
int id, i;
|
|
|
|
|
|
|
|
if (p == 0 || *printed(id = nodeid((Tree)p)))
|
|
|
|
return;
|
|
|
|
*printed(id) = 1;
|
|
|
|
for (i = 0; i < NELEMS(p->kids); i++)
|
|
|
|
printdag1(p->kids[i], fd, lev + 1);
|
|
|
|
printnode(p, fd, lev);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* printnode - print fields of dag p */
|
|
|
|
static void printnode(Node p, int fd, int lev) {
|
|
|
|
if (p) {
|
|
|
|
FILE *f = fd == 1 ? stdout : stderr;
|
|
|
|
int i, id = nodeid((Tree)p);
|
|
|
|
fprint(f, "%c%d%s", lev == 0 ? '\'' : '#', id,
|
|
|
|
&" "[id < 10 ? 0 : id < 100 ? 1 : 2]);
|
|
|
|
fprint(f, "%s count=%d", opname(p->op), p->count);
|
|
|
|
for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++)
|
|
|
|
fprint(f, " #%d", nodeid((Tree)p->kids[i]));
|
|
|
|
if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type)
|
|
|
|
fprint(f, " {%t}", p->syms[0]->type);
|
|
|
|
else
|
|
|
|
for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++)
|
|
|
|
if (p->syms[i]->name)
|
|
|
|
fprint(f, " %s", p->syms[i]->name);
|
|
|
|
else
|
|
|
|
fprint(f, " %p", p->syms[i]);
|
|
|
|
fprint(f, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* typestab - emit stab entries for p */
|
|
|
|
static void typestab(Symbol p, void *cl) {
|
|
|
|
if (!isfunc(p->type) && (p->sclass == EXTERN || p->sclass == STATIC) && IR->stabsym)
|
|
|
|
(*IR->stabsym)(p);
|
|
|
|
else if ((p->sclass == TYPEDEF || p->sclass == 0) && IR->stabtype)
|
|
|
|
(*IR->stabtype)(p);
|
|
|
|
}
|
|
|
|
|