/* 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;
Sym *s;
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;
if(p->as == ABCASE) { /* initialization for dodata */
s = p->from.sym;
if(s->type == SBSS)
s->type = SDATA;
if(s->type != SDATA)
diag("BCASE of non-data: %s in %s\n%P",
s->name, TNAME, p);
}
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 == ABCASE || 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 != ABCASE && 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;