plan9fox/sys/src/cmd/1l/pass.c
2011-03-30 19:35:09 +03:00

674 lines
11 KiB
C

#include "l.h"
void
dodata(void)
{
int i;
Sym *s;
Prog *p;
long t, u;
if(debug['v'])
Bprint(&bso, "%5.2f dodata\n", cputime());
Bflush(&bso);
for(p = datap; p != P; p = p->link) {
s = p->from.sym;
if(s->type == SBSS)
s->type = SDATA;
if(s->type != SDATA)
diag("initialize non-data (%d): %s\n%P",
s->type, s->name, p);
t = p->from.offset + p->from.displace;
if(t > s->value)
diag("initialize bounds (%ld): %s\n%P",
s->value, s->name, p);
}
/* allocate small guys */
datsize = 0;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type != SDATA)
if(s->type != SBSS)
continue;
t = s->value;
if(t == 0) {
diag("%s: no size", s->name);
t = 1;
}
t = rnd(t, 4);;
s->value = t;
if(t > MINSIZ)
continue;
s->value = datsize;
datsize += t;
s->type = SDATA1;
}
/* allocate the rest of the data */
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type != SDATA) {
if(s->type == SDATA1)
s->type = SDATA;
continue;
}
t = s->value;
s->value = datsize;
datsize += t;
}
if(debug['j']) {
/*
* pad data with bss that fits up to next
* 8k boundary, then push data to 8k
*/
u = rnd(datsize, 8192);
u -= datsize;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type != SBSS)
continue;
t = s->value;
if(t > u)
continue;
u -= t;
s->value = datsize;
s->type = SDATA;
datsize += t;
}
datsize += u;
}
/* now the bss */
bsssize = 0;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type != SBSS)
continue;
t = s->value;
s->value = bsssize + datsize;
bsssize += t;
}
xdefine("bdata", SDATA, 0L);
xdefine("edata", SDATA, datsize);
xdefine("end", SBSS, datsize+bsssize);
}
Prog*
brchain(Prog *p)
{
int i;
for(i=0; i<20; i++) {
if(p == P || p->as != ABRA)
return p;
p = p->pcond;
}
return P;
}
void
follow(void)
{
Prog *p;
long o;
if(debug['v'])
Bprint(&bso, "%5.2f follow\n", cputime());
Bflush(&bso);
firstp = prg();
lastp = firstp;
xfol(textp);
lastp->link = P;
firstp = firstp->link;
o = 0; /* set */
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
p->stkoff = -1; /* initialization for stkoff */
if(p->as == ATEXT) {
p->stkoff = 0;
o = p->to.offset;
continue;
}
if(p->as == AADJSP && p->from.offset == 0) {
p->stkoff = o;
continue;
}
}
}
void
xfol(Prog *p)
{
Prog *q;
int i;
enum as a;
loop:
if(p == P)
return;
if(p->as == ATEXT)
curtext = p;
if(p->as == ABRA)
if((q = p->pcond) != P) {
p->mark = 1;
p = q;
if(p->mark == 0)
goto loop;
}
if(p->mark) {
/* copy up to 4 instructions to avoid branch */
for(i=0,q=p; i<4; i++,q=q->link) {
if(q == P)
break;
if(q == lastp)
break;
a = q->as;
if(a == ANOP) {
i--;
continue;
}
if(a == ABRA || a == ARTS || a == ARTE)
break;
if(q->pcond == P || q->pcond->mark)
continue;
if(a == ABSR || a == ADBF)
continue;
for(;;) {
if(p->as == ANOP) {
p = p->link;
continue;
}
q = copyp(p);
p = p->link;
q->mark = 1;
lastp->link = q;
lastp = q;
if(q->as != a || q->pcond == P || q->pcond->mark)
continue;
q->as = relinv(q->as);
p = q->pcond;
q->pcond = q->link;
q->link = p;
xfol(q->link);
p = q->link;
if(p->mark)
return;
goto loop;
}
} /* */
q = prg();
q->as = ABRA;
q->line = p->line;
q->to.type = D_BRANCH;
q->to.offset = p->pc;
q->pcond = p;
p = q;
}
p->mark = 1;
lastp->link = p;
lastp = p;
a = p->as;
if(a == ARTS || a == ABRA || a == ARTE)
return;
if(p->pcond != P)
if(a != ABSR) {
q = brchain(p->link);
if(q != P && q->mark)
if(a != ADBF) {
p->as = relinv(a);
p->link = p->pcond;
p->pcond = q;
}
xfol(p->link);
q = brchain(p->pcond);
if(q->mark) {
p->pcond = q;
return;
}
p = q;
goto loop;
}
p = p->link;
goto loop;
}
int
relinv(int a)
{
switch(a) {
case ABEQ: return ABNE;
case ABNE: return ABEQ;
case ABLE: return ABGT;
case ABLS: return ABHI;
case ABLT: return ABGE;
case ABMI: return ABPL;
case ABGE: return ABLT;
case ABPL: return ABMI;
case ABGT: return ABLE;
case ABHI: return ABLS;
case ABCS: return ABCC;
case ABCC: return ABCS;
case AFBEQ: return AFBNE;
case AFBF: return AFBT;
case AFBGE: return AFBLT;
case AFBGT: return AFBLE;
case AFBLE: return AFBGT;
case AFBLT: return AFBGE;
case AFBNE: return AFBEQ;
case AFBT: return AFBF;
}
diag("unknown relation: %s in %s", anames[a], TNAME);
return a;
}
void
patch(void)
{
long c;
Prog *p, *q;
Sym *s;
long vexit;
if(debug['v'])
Bprint(&bso, "%5.2f mkfwd\n", cputime());
Bflush(&bso);
mkfwd();
if(debug['v'])
Bprint(&bso, "%5.2f patch\n", cputime());
Bflush(&bso);
s = lookup("exit", 0);
vexit = s->value;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
if((p->as == ABSR || p->as == ARTS) && p->to.sym != S) {
s = p->to.sym;
if(s->type != STEXT) {
diag("undefined: %s in %s", s->name, TNAME);
s->type = STEXT;
s->value = vexit;
}
p->to.offset = s->value;
p->to.type = D_BRANCH;
}
if(p->to.type != D_BRANCH)
continue;
c = p->to.offset;
for(q = firstp; q != P;) {
if(q->forwd != P)
if(c >= q->forwd->pc) {
q = q->forwd;
continue;
}
if(c == q->pc)
break;
q = q->link;
}
if(q == P) {
diag("branch out of range in %s\n%P", TNAME, p);
p->to.type = D_NONE;
}
p->pcond = q;
}
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
p->mark = 0; /* initialization for follow */
if(p->pcond != P) {
p->pcond = brloop(p->pcond);
if(p->pcond != P)
if(p->to.type == D_BRANCH)
p->to.offset = p->pcond->pc;
}
}
}
#define LOG 5
void
mkfwd(void)
{
Prog *p;
int i;
long dwn[LOG], cnt[LOG];
Prog *lst[LOG];
for(i=0; i<LOG; i++) {
if(i == 0)
cnt[i] = 1; else
cnt[i] = LOG * cnt[i-1];
dwn[i] = 1;
lst[i] = P;
}
i = 0;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
i--;
if(i < 0)
i = LOG-1;
p->forwd = P;
dwn[i]--;
if(dwn[i] <= 0) {
dwn[i] = cnt[i];
if(lst[i] != P)
lst[i]->forwd = p;
lst[i] = p;
}
}
}
Prog*
brloop(Prog *p)
{
int c;
Prog *q;
c = 0;
for(q = p; q != P; q = q->pcond) {
if(q->as != ABRA)
break;
c++;
if(c >= 5000)
return P;
}
return q;
}
void
dostkoff(void)
{
Prog *p, *q, *qq;
long s, t;
int a;
Optab *o;
if(debug['v'])
Bprint(&bso, "%5.2f stkoff\n", cputime());
Bflush(&bso);
s = 0;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT) {
curtext = p;
s = p->to.offset;
if(s == 0)
continue;
p = nprg(p);
p->as = AADJSP;
p->from.type = D_CONST;
p->from.offset = s;
p->stkoff = 0;
continue;
}
t = 0;
for(q = p; q != P; q = q->pcond) {
if(q->as == ATEXT)
break;
if(q->stkoff >= 0)
if(q->stkoff != s)
diag("stack offset %ld is %ld sb %ld in %s\n%P",
q->pc, q->stkoff, s, TNAME, p);
q->stkoff = s;
if(t++ > 100) {
diag("loop in stack offset 1: %P", p);
break;
}
}
o = &optab[p->as];
if(p->to.type == D_TOS)
s -= o->dstsp;
if(p->from.type == D_TOS)
s -= o->srcsp;
if(p->as == AADJSP)
s += p->from.offset;
if(p->as == APEA)
s += 4;
t = 0;
for(q = p->link; q != P; q = q->pcond) {
if(q->as == ATEXT) {
q = P;
break;
}
if(q->stkoff >= 0)
break;
if(t++ > 100) {
diag("loop in stack offset 2: %P", p);
break;
}
}
if(q == P || q->stkoff == s)
continue;
if(p->as == ABRA || p->as == ARTS || p->as == ARTE) {
s = q->stkoff;
continue;
}
t = q->stkoff - s;
s = q->stkoff;
p = nprg(p);
p->as = AADJSP;
p->stkoff = s - t;
p->from.type = D_CONST;
p->from.offset = t;
}
if(debug['v'])
Bprint(&bso, "%5.2f rewrite\n", cputime());
Bflush(&bso);
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
a = p->from.type & D_MASK;
if(a == D_AUTO)
p->from.offset += p->stkoff;
if(a == D_PARAM)
p->from.offset += p->stkoff + 4;
a = p->to.type & D_MASK;
if(a == D_AUTO)
p->to.offset += p->stkoff;
if(a == D_PARAM)
p->to.offset += p->stkoff + 4;
switch(p->as) {
default:
continue;
case AMOVW:
if(p->from.type != D_CCR)
continue;
a = p->to.type;
if((a < D_R0 || a > D_R0+7) && a != D_TOS)
diag("bad dest for MOVCC %P", p);
p->as = ALEA;
p->from.type = I_INDIR|(D_A0+7);
p->from.offset = -2;
p->to.type = D_A0+7;
p = nprg(p);
p->as = ABSR;
p->to.type = D_BRANCH;
p->pcond = prog_ccr;
p->to.sym = prog_ccr->from.sym;
if(a != D_TOS) {
p = nprg(p);
p->as = AMOVW;
p->from.type = D_TOS;
p->to.type = a;
}
continue;
case AEXTBL:
a = p->to.type;
if(a < D_R0 || a > D_R0+7)
diag("bad dest for EXTB");
p->as = AEXTBW;
p = nprg(p);
p->as = AEXTWL;
p->to.type = a;
continue;
case AMULSL:
case AMULUL:
qq = prog_mull;
goto mdcom;
case ADIVSL:
qq = prog_divsl;
goto mdcom;
case ADIVUL:
qq = prog_divul;
mdcom:
if(debug['m'])
continue;
a = p->to.type;
if(a < D_R0 || a > D_R0+7)
diag("bad dest for mul/div");
p->as = AMOVL;
p->to.type = D_TOS;
p = nprg(p);
p->as = AMOVL;
p->from.type = a;
p->to.type = D_TOS;
p = nprg(p);
p->as = ABSR;
p->to.type = D_BRANCH;
p->pcond = qq;
p->to.sym = qq->from.sym;
p = nprg(p);
p->as = AMOVL;
p->from.type = D_TOS;
p->to.type = a;
p = nprg(p);
p->as = AMOVL;
p->from.type = D_TOS;
p->to.type = a+1;
if(qq == prog_mull)
p->to.type = a;
continue;
case ARTS:
break;
}
if(p->stkoff == 0)
continue;
p->as = AADJSP;
p->from.type = D_CONST;
p->from.offset = -p->stkoff;
p = nprg(p);
p->as = ARTS;
p->stkoff = 0;
}
}
long
atolwhex(char *s)
{
long n;
int f;
n = 0;
f = 0;
while(*s == ' ' || *s == '\t')
s++;
if(*s == '-' || *s == '+') {
if(*s++ == '-')
f = 1;
while(*s == ' ' || *s == '\t')
s++;
}
if(s[0]=='0' && s[1]){
if(s[1]=='x' || s[1]=='X'){
s += 2;
for(;;){
if(*s >= '0' && *s <= '9')
n = n*16 + *s++ - '0';
else if(*s >= 'a' && *s <= 'f')
n = n*16 + *s++ - 'a' + 10;
else if(*s >= 'A' && *s <= 'F')
n = n*16 + *s++ - 'A' + 10;
else
break;
}
} else
while(*s >= '0' && *s <= '7')
n = n*8 + *s++ - '0';
} else
while(*s >= '0' && *s <= '9')
n = n*10 + *s++ - '0';
if(f)
n = -n;
return n;
}
void
undef(void)
{
int i;
Sym *s;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
if(s->type == SXREF)
diag("%s: not defined", s->name);
}
void
initmuldiv1(void)
{
lookup("_mull", 0)->type = SXREF;
lookup("_divsl", 0)->type = SXREF;
lookup("_divul", 0)->type = SXREF;
lookup("_ccr", 0)->type = SXREF;
}
void
initmuldiv2(void)
{
Sym *s1, *s2, *s3, *s4;
Prog *p;
if(prog_mull != P)
return;
s1 = lookup("_mull", 0);
s2 = lookup("_divsl", 0);
s3 = lookup("_divul", 0);
s4 = lookup("_ccr", 0);
for(p = firstp; p != P; p = p->link)
if(p->as == ATEXT) {
if(p->from.sym == s1)
prog_mull = p;
if(p->from.sym == s2)
prog_divsl = p;
if(p->from.sym == s3)
prog_divul = p;
if(p->from.sym == s4)
prog_ccr = p;
}
if(prog_mull == P) {
diag("undefined: %s", s1->name);
prog_mull = curtext;
}
if(prog_divsl == P) {
diag("undefined: %s", s2->name);
prog_divsl = curtext;
}
if(prog_divul == P) {
diag("undefined: %s", s3->name);
prog_divul = curtext;
}
if(prog_ccr == P) {
diag("undefined: %s", s4->name);
prog_ccr = curtext;
}
}