yo-compiler/gen.c
2024-11-03 16:28:52 +09:00

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 != nil);
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;
}
}