481 lines
7.3 KiB
C
481 lines
7.3 KiB
C
#include "yo.h"
|
|
|
|
static int addrmode[Rend] =
|
|
{
|
|
/* Rreg */ Afp,
|
|
/* Rmreg */ Amp,
|
|
/* Roff */ Aoff,
|
|
/* Rnoff */ Anoff,
|
|
/* Rdesc */ Adesc,
|
|
/* Rdescp */ Adesc,
|
|
/* Rconst */ Aimm,
|
|
/* Ralways */ Aerr,
|
|
/* Radr */ Afpind,
|
|
/* Rmadr */ Ampind,
|
|
/* Rcant */ Aerr,
|
|
/* Rpc */ Apc,
|
|
/* Rmpc */ Aerr,
|
|
/* Rareg */ Aerr,
|
|
/* Ramreg */ Aerr,
|
|
/* Raadr */ Aerr,
|
|
/* Ramadr */ Aerr,
|
|
/* Rldt */ Aldt,
|
|
};
|
|
|
|
static int blockstklen;
|
|
static Inst zinst;
|
|
static Decl *wtemp;
|
|
static Node *ntoz;
|
|
static int ntemp;
|
|
|
|
int *blockstk;
|
|
int blockdep;
|
|
int nblock;
|
|
int blocks;
|
|
|
|
Node retnode;
|
|
Inst *lastinst, *firstinst;
|
|
|
|
int
|
|
pushblock(void)
|
|
{
|
|
if(blockdep >= blockstklen){
|
|
blockstklen = blockdep += 32;
|
|
blockstk = realloc(blockstk, blockstklen*sizeof(blockstk));
|
|
}
|
|
blockstk[blockdep++] = blocks;
|
|
return blocks = nblock++;
|
|
}
|
|
|
|
void
|
|
repushblock(int b)
|
|
{
|
|
blockstk[blockdep++] = blocks;
|
|
blocks = b;
|
|
}
|
|
|
|
void
|
|
popblock(void)
|
|
{
|
|
blocks = blockstk[--blockdep];
|
|
}
|
|
|
|
Inst*
|
|
nextinst(void)
|
|
{
|
|
Inst *in = lastinst->next;
|
|
if(in)
|
|
return in;
|
|
in = new(sizeof(Inst));
|
|
*in = zinst;
|
|
lastinst->next = in;
|
|
return in;
|
|
}
|
|
|
|
|
|
Inst*
|
|
mkinst(void)
|
|
{
|
|
Inst *in = lastinst->next;
|
|
if(in == nil){
|
|
in = new(sizeof(Inst));
|
|
*in = zinst;
|
|
lastinst->next = in;
|
|
}
|
|
lastinst = in;
|
|
assert(blocks >= 0);
|
|
in->block = blocks;
|
|
return in;
|
|
}
|
|
|
|
void
|
|
tinit(void)
|
|
{
|
|
wtemp = nil;
|
|
}
|
|
|
|
void
|
|
genstart(void)
|
|
{
|
|
ntoz = nil;
|
|
Decl *d = mkdecl(Dlocal, tint);
|
|
d->sym = enter(".ret", 0);
|
|
d->offset = IBY2WD * REGRET;
|
|
|
|
zinst = (Inst){0};
|
|
zinst.op = INOP;
|
|
zinst.sm = Anone;
|
|
zinst.dm = Anone;
|
|
zinst.mm = Anone;
|
|
|
|
firstinst = new(sizeof(Inst));
|
|
*firstinst = zinst;
|
|
lastinst = firstinst;
|
|
|
|
retnode.op = Oname;
|
|
retnode.addable = Rreg;
|
|
retnode.ty = tint;
|
|
retnode.decl = d;
|
|
|
|
blocks = -1;
|
|
blockdep = 0;
|
|
nblock = 0;
|
|
}
|
|
|
|
Addr
|
|
genaddr(Node *n)
|
|
{
|
|
Addr a = {0};
|
|
if(n == nil)
|
|
return a;
|
|
switch(n->addable){
|
|
case Rareg:
|
|
a = genaddr(n->l);
|
|
if(n->op == Oadd)
|
|
a.reg += n->r->val;
|
|
break;
|
|
case Rreg:
|
|
if(n->decl)
|
|
a.decl = n->decl;
|
|
else
|
|
a = genaddr(n->l);
|
|
break;
|
|
case Rconst:
|
|
a.offset = n->val;
|
|
break;
|
|
case Radr:
|
|
a = genaddr(n->l);
|
|
break;
|
|
case Raadr:
|
|
a = genaddr(n->l);
|
|
if(n->op == Oadd)
|
|
a.offset += n->r->val;
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
return a;
|
|
}
|
|
|
|
int
|
|
sameaddr(Node *n, Node *m)
|
|
{
|
|
if(n->addable != m->addable)
|
|
return 0;
|
|
Addr a = genaddr(n);
|
|
Addr b = genaddr(m);
|
|
return a.offset==b.offset && a.reg==b.reg && a.decl == b.decl;
|
|
}
|
|
|
|
Inst*
|
|
genmove(Type *t, Node *s, Node *d)
|
|
{
|
|
static u8 mvtab[] = {
|
|
[Tptr] = IMOVW,
|
|
[Tint] = IMOVW,
|
|
[Tbool] = IMOVW,
|
|
[Ttup] = IMOVM,
|
|
[Tarray] = IARRAY,
|
|
[Tslice] = IMOVM,
|
|
[Tstruct] = IMOVM,
|
|
};
|
|
Inst *in = nil;
|
|
Addr reg = {0};
|
|
int regm = Anone;
|
|
u8 op = mvtab[t->kind];
|
|
assert(op!=0);
|
|
switch(t->kind){
|
|
case Tarray:
|
|
case Tslice:
|
|
case Tstruct:
|
|
case Ttup:
|
|
assert(t->size != 0);
|
|
regm = Aimm;
|
|
reg.offset = t->size;
|
|
break;
|
|
}
|
|
in = mkinst();
|
|
in->op = op;
|
|
if(s){
|
|
in->s = genaddr(s);
|
|
in->sm = addrmode[s->addable];
|
|
}
|
|
in->m = reg;
|
|
in->mm = regm;
|
|
if(d){
|
|
in->d = genaddr(d);
|
|
in->dm = addrmode[d->addable];
|
|
}
|
|
return in;
|
|
}
|
|
|
|
Inst*
|
|
genrawop(int op, Node *s, Node *m, Node *d)
|
|
{
|
|
Inst *in = mkinst();
|
|
in->op = op;
|
|
if(s){
|
|
in->s = genaddr(s);
|
|
in->sm = addrmode[s->addable];
|
|
}
|
|
if(m){
|
|
in->m = genaddr(m);
|
|
in->mm = addrmode[m->addable];
|
|
assert(in->mm != Ampind);
|
|
assert(in->mm != Afpind);
|
|
}
|
|
if(d){
|
|
in->d = genaddr(d);
|
|
in->dm = addrmode[d->addable];
|
|
}
|
|
return in;
|
|
}
|
|
|
|
Inst*
|
|
genop(int op, Node *s, Node *m, Node *d)
|
|
{
|
|
static u8 disoptab[Oend][Tend] =
|
|
{
|
|
[Olt] = {[Tint]=ILTW,[Tbool]=ILTW},
|
|
[Oeq] = {[Tint]=IEQW,[Tbool]=IEQW},
|
|
[Oleq] ={[Tint]=ILEQW,[Tbool]=ILEQW},
|
|
[Oandand] = {[Tint]=IEQW,[Tbool]=IEQW},
|
|
[Ooror] = {[Tint]=IADDW,[Tbool]=IADDW},
|
|
[Oadd] = {[Tint]=IADDW,},
|
|
[Osub] = {[Tint]=ISUBW,},
|
|
[Omul] = {[Tint]=IMULW,},
|
|
};
|
|
Inst *in = mkinst();
|
|
int iop = disoptab[op][d->ty->kind];
|
|
assert(iop != 0);
|
|
in->op = iop;
|
|
if(s){
|
|
in->s = genaddr(s);
|
|
in->sm = addrmode[s->addable];
|
|
}
|
|
if(m){
|
|
in->m = genaddr(m);
|
|
in->mm = addrmode[m->addable];
|
|
assert(in->mm != Ampind);
|
|
assert(in->mm != Afpind);
|
|
}
|
|
if(d){
|
|
in->d = genaddr(d);
|
|
in->dm = addrmode[d->addable];
|
|
}
|
|
return in;
|
|
}
|
|
|
|
void
|
|
addprint(FILE *f, int am, Addr *a)
|
|
{
|
|
switch(am){
|
|
case Anone:
|
|
return;
|
|
case Afp:
|
|
fprintf(f, "%u(fp)", a->reg);
|
|
break;
|
|
case Aimm:
|
|
fprintf(f, "$%u", a->offset);
|
|
break;
|
|
case Afpind:
|
|
fprintf(f, "%u(%u(fp))", a->offset, a->reg);
|
|
break;
|
|
case Adesc:
|
|
fprintf(f, "$%u", a->offset+a->reg);
|
|
break;
|
|
case Apc:
|
|
fprintf(f, "$%u", a->reg+a->offset);
|
|
break;
|
|
case Amp:
|
|
fprintf(f, "%u(mp)",a->reg);
|
|
break;
|
|
case Aldt:
|
|
fprintf(f, "$%u", a->reg);
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
instconv(FILE *f, Inst *in)
|
|
{
|
|
char *comma = "";
|
|
|
|
if(in == nil)
|
|
return;
|
|
char* op = instname[in->op];
|
|
fprintf(f, "\t%s\t", op);
|
|
if(op == INOP)
|
|
return;
|
|
if(in->sm != Anone){
|
|
addprint(f, in->sm, &in->s);
|
|
comma = ", ";
|
|
}
|
|
if(in->mm != Anone){
|
|
fprintf(f, "%s", comma);
|
|
addprint(f, in->mm, &in->m);
|
|
comma = ", ";
|
|
}
|
|
if(in->dm != Anone){
|
|
fprintf(f, "%s", comma);
|
|
addprint(f, in->dm, &in->d);
|
|
comma = "";
|
|
}
|
|
fprintf(f, "\n");
|
|
}
|
|
|
|
Node*
|
|
talloc(Node *n, Type *t, Node *nok)
|
|
{
|
|
Decl *ok = nok == nil ? nil : nok->decl;
|
|
|
|
if(ok==nil||ok->tref==0)
|
|
ok = nil;
|
|
*n = (Node){0};
|
|
n->op = Oname;
|
|
n->addable = Rreg;
|
|
n->ty = t;
|
|
if(ok != nil
|
|
&&ok->ty->kind == t->kind
|
|
&&ok->ty->size == t->size){
|
|
ok->tref++;
|
|
n->decl = ok;
|
|
return n;
|
|
}
|
|
for(Decl *d = wtemp; d != nil; d = d->next){
|
|
if(d->tref == 1
|
|
&& d->ty->kind == t->kind
|
|
&& d->ty->size == t->size){
|
|
d->tref++;
|
|
n->decl = d;
|
|
return n;
|
|
}
|
|
}
|
|
char buf[64] = {0};
|
|
sprintf(buf, ".t%d", ntemp++);
|
|
Decl *d = mkdecl(Dlocal, t);
|
|
d->sym = enter(buf, 0);
|
|
d->tref = 2;
|
|
n->decl = d;
|
|
d->next = wtemp;
|
|
wtemp = d;
|
|
|
|
return n;
|
|
}
|
|
|
|
void
|
|
tfree(Node *n)
|
|
{
|
|
if(n == nil || n->decl == nil || n->decl->tref == 0)
|
|
return;
|
|
assert(n->decl->tref > 1);
|
|
if(--n->decl->tref == 1){
|
|
return;
|
|
}
|
|
}
|
|
|
|
void
|
|
tfreenow(void)
|
|
{
|
|
assert(ntoz == nil);
|
|
}
|
|
|
|
int
|
|
align(int off)
|
|
{
|
|
while(off % IBY2WD)
|
|
off++;
|
|
return off;
|
|
}
|
|
|
|
int
|
|
idoffsets(Decl *id, long offset, int al)
|
|
{
|
|
if(id==nil || id->flag)
|
|
return align(offset);
|
|
for(; id; id = id->next){
|
|
id->flag = 1;
|
|
if(id->store == Dlocal && id->link){
|
|
if(id->link->flag == 0)
|
|
idoffsets(id->link, offset, al);
|
|
id->offset = id->link->offset;
|
|
continue;
|
|
}
|
|
offset = align(offset);
|
|
id->offset = offset;
|
|
offset += id->ty->size;
|
|
if(id->nid == 0 && (id->next == nil || id->next->nid != 0))
|
|
offset = align(offset);
|
|
}
|
|
return align(offset);
|
|
}
|
|
|
|
Decl*
|
|
tdecls(void)
|
|
{
|
|
for(Decl *d = wtemp; d; d=d->next)
|
|
assert(d->tref == 1);
|
|
return wtemp;
|
|
}
|
|
|
|
int
|
|
resolvepcs(Inst *inst)
|
|
{
|
|
int pc = 0;
|
|
for(Inst *in=inst; in; in=in->next){
|
|
Decl *d = in->s.decl;
|
|
if(d){
|
|
in->s.reg += d->offset;
|
|
}
|
|
d = in->m.decl;
|
|
if(d){
|
|
in->m.reg += d->offset;
|
|
}
|
|
d = in->d.decl;
|
|
if(d){
|
|
if(in->dm == Apc){
|
|
in->d.offset = d->pc->pc;
|
|
}else{
|
|
in->d.reg += d->offset;
|
|
}
|
|
}
|
|
in->pc = pc++;
|
|
}
|
|
for(Inst *in=inst; in; in=in->next){
|
|
Decl *d =in->s.decl;
|
|
if(d && in->sm == Apc)
|
|
in->s.offset = d->pc->pc;
|
|
d = in->d.decl;
|
|
if(d != nil && in->dm == Apc)
|
|
in->d.offset = d->pc->pc;
|
|
if(in->branch){
|
|
in->dm = Apc;
|
|
in->d.offset = in->branch->pc;
|
|
}
|
|
}
|
|
return pc;
|
|
}
|
|
|
|
int
|
|
idindices(Decl *id)
|
|
{
|
|
int i = 0;
|
|
for(; id; id=id->next){
|
|
usetype(id->ty);
|
|
id->offset = i++;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
void
|
|
ipatch(Inst *b, Inst *d)
|
|
{
|
|
Inst *n;
|
|
for(; b; b = n){
|
|
n = b->branch;
|
|
b->branch = d;
|
|
}
|
|
} |