📄 gen.c
字号:
#include "c.h"
extern Symbol intreg[];
//#define DODEBUG
#define NORMAL_REG_ORDER
#define readsreg(p) \
(generic((p)->op)==INDIR && (p)->kids[0]->op==VREG+P)
#define setsrc(d) ((d) && (d)->x.regnode && \
(d)->x.regnode->set == src->x.regnode->set && \
(d)->x.regnode->mask&src->x.regnode->mask)
#define relink(a, b) ((b)->x.prev = (a), (a)->x.next = (b))
static Symbol askfixedreg ARGS((Symbol));
static Symbol askreg ARGS((Symbol, unsigned*));
static void blkunroll ARGS((int, int, int, int, int, int, int[]));
static void docall ARGS((Node));
static void dumpcover ARGS((Node, int, int));
#ifdef DODEBUG
static void dumpregs ARGS((char *, char *, char *,char *));
#endif
static void dumprule ARGS((int));
void dumptree ARGS((Node,int));
unsigned emitasm ARGS((Node, int));
static void genreload ARGS((Node, Symbol, int));
static void genspill ARGS((Symbol, Node, Symbol));
static Symbol getreg ARGS((Symbol, unsigned*, Node,int));
static int getrule ARGS((Node, int));
void linearize ARGS((Node, Node));
int moveself ARGS((Node));
static void prelabel ARGS((Node));
static Node* prune ARGS((Node, Node*));
static void putreg ARGS((Symbol));
static void ralloc ARGS((Node));
static void reduce ARGS((Node, int));
static int reprune ARGS((Node*, int, int, Node));
int requate ARGS((Node));
static Node reuse ARGS((Node, int));
static void rewrite ARGS((Node));
static Symbol spillee ARGS((Symbol, Node));
static void spillr ARGS((Symbol, Node));
static int trashes ARGS((Node, Node));
static int uses ARGS((Node, unsigned));
int offset;
int maxoffset;
int framesize;
int argoffset;
int maxargoffset;
int dalign, salign;
int bflag = 0; /* omit */
int dflag = 0;
int swap;
static int unsafe=1;
unsigned (*emitter) ARGS((Node, int)) = emitasm;
static char NeedsReg[] = {
0, /* unused */
1, /* CNST */
0, 0, /* ARG ASGN */
1, /* INDIR */
1, 1, 1, 1, /* CVC CVD CVF CVI */
1, 1, 1, 1, /* CVP CVS CVU NEG */
1, /* CALL */
1, /* LOAD */
0, /* RET */
1, 1, 1, /* ADDRG ADDRF ADDRL */
1, 1, 1, 1, 1, /* ADD SUB LSH MOD RSH */
1, 1, 1, 1, /* BAND BCOM BOR BXOR */
1, 1, /* DIV MUL */
0, 0, 0, 0, 0, 0, /* EQ GE GT LE LT NE */
0, 0, /* JUMP LABEL */
1
};
Symbol rmap[16];
Node head;
unsigned freemask[2];
unsigned usedmask[2];
unsigned tmask[2];
unsigned vmask[2];
Symbol mkreg(char *fmt,int n,int mask,int set)
{
Symbol p;
NEW0(p, PERM);
p->name = fmt+1;
p->x.name = stringf(fmt, n);
NEW0(p->x.regnode, PERM);
p->x.regnode->number = (short)n;
p->x.regnode->mask = mask<<n;
p->x.regnode->set = (short)set;
return p;
}
Symbol mkwildcard(Symbol *syms)
{
Symbol p;
NEW0(p, PERM);
p->x.name = "wildcard";
p->x.wildcard = syms;
return p;
}
void mkauto(Symbol p)
{
assert(p->sclass == AUTO);
offset = roundup(offset + p->type->size, p->type->align);
p->x.offset = -offset;
if (hasExceptions)
p->x.offset -= 24;
if (glevel > 2)
p->x.offset -= 12;
p->x.name = stringd(p->x.offset);
}
void blockbeg(Env *e)
{
e->offset = offset;
e->freemask[IREG] = freemask[IREG];
e->freemask[FREG] = freemask[FREG];
}
void blockend(Env *e)
{
if (offset > maxoffset)
maxoffset = offset;
offset = e->offset;
freemask[IREG] = e->freemask[IREG];
freemask[FREG] = e->freemask[FREG];
}
int mkactual(int align,int size)
{
int n = roundup(argoffset, align);
argoffset = n + size;
return n;
}
static void docall(Node p)
{
FunctionHasCalls = 1;
p->syms[0] = intconst(argoffset);
if (argoffset > maxargoffset)
maxargoffset = argoffset;
argoffset = 0;
}
void blkcopy(int dreg,int doff,int sreg,int soff,int size,int tmp[])
{
assert(size >= 0);
if (size == 0)
return;
else if (size <= 2)
blkunroll(size, dreg, doff, sreg, soff, size, tmp);
else if (size == 3) {
blkunroll(2, dreg, doff, sreg, soff, 2, tmp);
blkunroll(1, dreg, doff+2, sreg, soff+2, 1, tmp);
}
else if (size <= 16) {
blkunroll(4, dreg, doff, sreg, soff, size&~3, tmp);
blkcopy(dreg, doff+(size&~3),
sreg, soff+(size&~3), size&3, tmp);
}
else
(*IR->x.blkloop)(dreg, doff, sreg, soff, size, tmp);
}
static void blkunroll(int k,int dreg,int doff,int sreg,int soff,int size,int tmp[])
{
int i;
assert(IR->x.max_unaligned_load);
if (k > IR->x.max_unaligned_load
&& (k > salign || k > dalign))
k = IR->x.max_unaligned_load;
for (i = 0; i+k < size; i += 2*k) {
(*IR->x.blkfetch)(k, soff+i, sreg, tmp[0]);
(*IR->x.blkfetch)(k, soff+i+k, sreg, tmp[1]);
(*IR->x.blkstore)(k, doff+i, dreg, tmp[0]);
(*IR->x.blkstore)(k, doff+i+k, dreg, tmp[1]);
}
if (i < size) {
(*IR->x.blkfetch)(k, i+soff, sreg, tmp[0]);
(*IR->x.blkstore)(k, i+doff, dreg, tmp[0]);
}
}
void parseflags(int argc,char *argv[])
{
int i;
for (i = 0; i < argc; i++)
if (strcmp(argv[i], "-d") == 0)
dflag = 1;
else if (strcmp(argv[i], "-b") == 0) /* omit */
bflag = 1; /* omit */
}
/*------------------------------------------------------------------------
Procedure: getrule ID:1
Purpose: This function just encapsulates the call to the
interface rule function. 14.3.382
Input:
Output:
Errors:
------------------------------------------------------------------------*/
static int getrule(Node p,int nt)
{
int rulenum;
assert(p);
rulenum = (*IR->x._rule)(p->x.state, nt);
if (rulenum == 0) {
assert(0);
}
return rulenum;
}
static void reduce(Node p,int nt)
{
int rulenum, i;
short *nts;
Node kids[10];
p = reuse(p, nt);
#ifdef PURIFY
rulenum = getrule(p, nt);
#else
rulenum = (*IR->x._rule)(p->x.state, nt);
#endif
nts = IR->x._nts[rulenum];
p->x.rulenum = rulenum;
(*IR->x._kids)(p, rulenum, kids);
for (i = 0; nts[i]; i++)
reduce(kids[i], nts[i]);
if (IR->x._isinstruction[rulenum]) {
assert(p->x.inst == 0 || p->x.inst == nt);
p->x.inst = (short)nt;
if (p->syms[RX] && p->syms[RX]->temporary) {
#ifdef DODEBUG
fprint(2, "(using %s)\n", p->syms[RX]->name);
#endif
p->syms[RX]->x.usecount++;
}
}
}
/*------------------------------------------------------------------------
Procedure: reuse ID:1
Purpose: The call to reuse sees if the reduction of node p using
nonterminal nt uses a 'bonus match'. If so, it returns
the common subexpression instead of p. The objective is
to reprocess the common subexpression and ignore the
temporary. It collaborates with reduce to recalculate
expressions that are cheaper to recalculate than to
store into a register.14.3.383
Input:
Output:
Errors:
------------------------------------------------------------------------*/
static Node reuse(Node p,int nt)
{
struct _state {
short cost[1];
};
Symbol r = p->syms[RX];
if (generic(p->op) == INDIR && p->kids[0]->op == VREG+P
&& r->u.t.cse && p->x.mayrecalc
&& ((struct _state*)r->u.t.cse->x.state)->cost[nt] == 0)
return r->u.t.cse;
else
return p;
}
int mayrecalc(Node p)
{
Node q;
assert(p && p->syms[RX]);
if (!p->syms[RX]->u.t.cse)
return 0;
for (q = head; q && q->x.listed; q = q->link)
if (generic(q->op) == ASGN
&& trashes(q->kids[0], p->syms[RX]->u.t.cse))
return 0;
p->x.mayrecalc = 1;
return 1;
}
static int trashes(Node p,Node q)
{
assert(p);
if (!q)
return 0;
/*
This read before syms[0]. It should be syms[RX] in my opinion. I leave both
*/
else if (p->op == q->op &&
(p->syms[RX] == q->syms[RX] || p->syms[0] == q->syms[0]))
return 1;
else
return trashes(p, q->kids[0])
|| trashes(p, q->kids[1]);
}
static Node *prune(Node p,Node pp[])
{
if (p == NULL)
return pp;
#if 0 /* here I have a problem. The origianl sources didn't make this assertion. Where does this come from? */
if(p->x.kids[2] != NULL) {
assert(0);
}
#endif
p->x.kids[0] = p->x.kids[1] = p->x.kids[2] = NULL;
if (p->x.inst == 0)
return prune(p->kids[1], prune(p->kids[0], pp));
else if (p->syms[RX] && p->syms[RX]->temporary
&& p->syms[RX]->x.usecount < 2) {
p->x.inst = 0;
#ifdef DODEBUG
fprint(2, "(clobbering %s)\n", p->syms[RX]->name);
#endif
return prune(p->kids[1], prune(p->kids[0], pp));
}
else {
prune(p->kids[1], prune(p->kids[0], &p->x.kids[0]));
*pp = p;
return pp + 1;
}
}
#define ck(i) return (i) ? 0 : LBURG_MAX
int range(Node p,int lo,int hi)
{
Symbol s = p->syms[0];
switch (p->op) {
case ADDRFP: ck(s->x.offset >= lo && s->x.offset <= hi);
case ADDRLP: ck(s->x.offset >= lo && s->x.offset <= hi);
case CNSTC: ck(s->u.c.v.sc >= lo && s->u.c.v.sc <= hi);
case CNSTI: ck(s->u.c.v.i >= lo && s->u.c.v.i <= hi);
case CNSTS: ck(s->u.c.v.ss >= lo && s->u.c.v.ss <= hi);
case CNSTU: ck(s->u.c.v.u >= (unsigned)lo && s->u.c.v.u <= (unsigned)hi);
case CNSTP: ck(s->u.c.v.p == 0 && lo <= 0 && hi >= 0);
}
return LBURG_MAX;
}
void dumptree(Node p,int level)
{
fprint(2, "%s(", IR->x._opname[p->op]);
if (IR->x._arity[p->op] == 0 && p->syms[0])
fprint(2, "%s", p->syms[0]->name);
else if (IR->x._arity[p->op] == 1)
dumptree(p->kids[0],level+1);
else if (IR->x._arity[p->op] == 2) {
dumptree(p->kids[0],level+1);
fprint(2, ", ");
dumptree(p->kids[1],level+1);
}
fprint(2, ")");
}
void ildumptree(Node p,int level)
{
fprintf(ilFile, "%s(", IR->x._opname[p->op]);
if (IR->x._arity[p->op] == 0 && p->syms[0]) {
if (p->syms[0]->name == NULL)
fprintf(ilFile,"%s",p->syms[0]->x.name);
else
fprintf(ilFile, "%s", p->syms[0]->name);
}
else if (IR->x._arity[p->op] == 1)
ildumptree(p->kids[0],level+1);
else if (IR->x._arity[p->op] == 2) {
int i;
fprintf(ilFile,"\n");
for (i=0; i<=level;i++) fprintf(ilFile," ");
ildumptree(p->kids[0],level+1);
fprintf(ilFile, ",\n");
for(i=0; i<=level;i++) fprintf(ilFile," ");
ildumptree(p->kids[1],level+1);
}
fprintf(ilFile, ")");
}
static void ildumprule(int rulenum)
{
assert(rulenum);
fprintf(ilFile, "%s / %s", IR->x._string[rulenum],
IR->x._templates[rulenum]);
if (!IR->x._isinstruction[rulenum])
fprintf(ilFile, "\n");
}
void ildumpcover(Node p,int nt,int in)
{
int rulenum, i;
short *nts;
Node kids[10];
p = reuse(p, nt);
rulenum = (*IR->x._rule)(p->x.state, nt);
nts = IR->x._nts[rulenum];
for (i = 0; i < in; i++)
fprintf(ilFile, " ");
ildumprule(rulenum);
(*IR->x._kids)(p, rulenum, kids);
for (i = 0; nts[i]; i++)
ildumpcover(kids[i], nts[i], in+1);
}
#ifdef DODEBUG
static void dumpcover(Node p,int nt,int in)
{
int rulenum, i;
short *nts;
Node kids[10];
p = reuse(p, nt);
#ifdef PURIFY
rulenum = getrule(p, nt);
#else
rulenum = (*IR->x._rule)(p->x.state, nt);
#endif
nts = IR->x._nts[rulenum];
fprint(2, "dumpcover(%x) = ", p);
for (i = 0; i < in; i++)
fprint(2, " ");
dumprule(rulenum);
(*IR->x._kids)(p, rulenum, kids);
for (i = 0; nts[i]; i++)
dumpcover(kids[i], nts[i], in+1);
}
static void dumprule(int rulenum)
{
assert(rulenum);
fprint(2, "%s / %s", IR->x._string[rulenum],
IR->x._templates[rulenum]);
if (!IR->x._isinstruction[rulenum])
fprint(2, "\n");
}
#endif /* DODEBUG */
/*------------------------------------------------------------------------
Procedure: emitasm ID:1
Purpose: Processes a partially linearized tree. List elements are
the roots of subtrees for instructions. It traces the
sub-instructions which correspond to addressing modes
and other calculations inside a logical instruction. The
driver of emitasm, 'emit' ensures that this instructions
are seen in the right order.
It sets the x.emitted flag as it emits them. 14.6.392
Input:
Output:
Errors:
------------------------------------------------------------------------*/
extern int hasAllocA;
int NeedsLineReset;
unsigned emitasm(Node p,int nt)
{
int rulenum,booleanAsgn,genericOp;
short *nts; /* Used only in a recursive call
Contains the nonterminals for the rule's pattern */
register char *fmt;
Node kids[10];
int isinstruction;
char *oldbp;
extern int cseg;
int NeedsCallReset=0;
char newfmt[40];
p = reuse(p, nt);
#ifdef PURIFY
rulenum = getrule(p, nt);
#else
rulenum = (*IR->x._rule)(p->x.state, nt);
#endif
nts = IR->x._nts[rulenum];
fmt = IR->x._templates[rulenum];
assert(fmt);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -