plan9fox/sys/src/cmd/2c/reg.c
2011-03-30 19:35:09 +03:00

1276 lines
22 KiB
C

#include "gc.h"
Reg*
rega(void)
{
Reg *r;
r = freer;
if(r == R) {
r = alloc(sizeof(*r));
} else
freer = r->link;
*r = zreg;
return r;
}
int
rcmp(const void *a1, const void *a2)
{
Rgn *p1, *p2;
int c1, c2;
p1 = (Rgn*)a1;
p2 = (Rgn*)a2;
c1 = p2->costr;
if(p2->costa > c1)
c1 = p2->costa;
c2 = p1->costr;
if(p1->costa > c2)
c2 = p1->costa;
if(c1 -= c2)
return c1;
return p2->varno - p1->varno;
}
void
regopt(Prog *p)
{
Reg *r, *r1, *r2;
Prog *p1;
int i, z;
long val, initpc, npc;
ulong vreg;
Bits bit;
Var *v;
struct {
long m;
long c;
Reg* p;
} log5[6], *lp;
firstr = R;
lastr = R;
nvar = 0;
for(z=0; z<BITS; z++) {
externs.b[z] = 0;
params.b[z] = 0;
addrs.b[z] = 0;
}
regbits = RtoB(0) | /* return reg */
AtoB(6) | AtoB(7) | /* sp and sb */
FtoB(0) | FtoB(1); /* floating return reg */
for(i=0; i<NREG; i++) {
if(regused[i])
regbits |= RtoB(i);
if(fregused[i])
regbits |= FtoB(i);
if(aregused[i])
regbits |= AtoB(i);
}
/*
* pass 1
* build aux data structure
* allocate pcs
* find use and set of variables
*/
val = 5L * 5L * 5L * 5L * 5L;
lp = log5;
for(i=0; i<5; i++) {
lp->m = val;
lp->c = 0;
lp->p = R;
val /= 5L;
lp++;
}
val = 0;
for(; p != P; p = p->link) {
switch(p->as) {
case ADATA:
case AGLOBL:
case ANAME:
case ASIGNAME:
continue;
}
r = rega();
if(firstr == R) {
firstr = r;
lastr = r;
} else {
lastr->link = r;
r->p1 = lastr;
lastr->s1 = r;
lastr = r;
}
r->prog = p;
r->pc = val;
val++;
lp = log5;
for(i=0; i<5; i++) {
lp->c--;
if(lp->c <= 0) {
lp->c = lp->m;
if(lp->p != R)
lp->p->log5 = r;
lp->p = r;
(lp+1)->c = 0;
break;
}
lp++;
}
r1 = r->p1;
if(r1 != R)
switch(r1->prog->as) {
case ABRA:
case ARTS:
case ARTE:
r->p1 = R;
r1->s1 = R;
}
bit = mkvar(&p->from, AGOK);
if(bany(&bit))
switch(p->as) {
case ALEA:
if(!(mvbits & B_INDIR))
for(z=0; z<BITS; z++)
addrs.b[z] |= bit.b[z];
default:
if(mvbits & B_ADDR)
for(z=0; z<BITS; z++)
addrs.b[z] |= bit.b[z];
for(z=0; z<BITS; z++)
r->use1.b[z] |= bit.b[z];
}
bit = mkvar(&p->to, p->as);
if(bany(&bit))
switch(p->as) {
case ABSR: /* funny */
for(z=0; z<BITS; z++)
addrs.b[z] |= bit.b[z];
goto def;
case APEA:
if(!(mvbits & B_INDIR))
for(z=0; z<BITS; z++)
addrs.b[z] |= bit.b[z];
def:
case ACMPB: case ACMPW: case ACMPL:
case AFCMPF: case AFCMPD:
case ATSTB: case ATSTW: case ATSTL:
case AFTSTF: case AFTSTD:
case ABFEXTU: case ABFEXTS:
if(mvbits & B_ADDR)
for(z=0; z<BITS; z++)
addrs.b[z] |= bit.b[z];
for(z=0; z<BITS; z++)
r->use2.b[z] |= bit.b[z];
break;
default:
diag(Z, "reg: unknown asop: %A", p->as);
case AADDB: case AADDW: case AADDL:
case ASUBB: case ASUBW: case ASUBL:
case AANDB: case AANDW: case AANDL:
case AORB: case AORW: case AORL:
case AEORB: case AEORW: case AEORL:
case ABFINS:
for(z=0; z<BITS; z++)
r->use2.b[z] |= bit.b[z];
case ANOP:
case AMOVB: case AMOVW: case AMOVL:
case AFMOVEB: case AFMOVEW: case AFMOVEL:
case ACLRB: case ACLRW: case ACLRL:
case AFMOVEF: case AFMOVED:
if(mvbits & B_INDIR)
for(z=0; z<BITS; z++)
r->use2.b[z] |= bit.b[z];
else
for(z=0; z<BITS; z++)
r->set.b[z] |= bit.b[z];
break;
}
}
if(firstr == R)
return;
initpc = pc - val;
npc = val;
/*
* pass 2
* turn branch references to pointers
* build back pointers
*/
for(r = firstr; r != R; r = r->link) {
p = r->prog;
if(p->to.type == D_BRANCH) {
val = p->to.offset - initpc;
r1 = firstr;
while(r1 != R) {
r2 = r1->log5;
if(r2 != R && val >= r2->pc) {
r1 = r2;
continue;
}
if(r1->pc == val)
break;
r1 = r1->link;
}
if(r1 == R) {
diag(Z, "ref not found\n%L:%P", p->lineno, p);
continue;
}
if(r1 == r) {
diag(Z, "ref to self");
continue;
}
r->s2 = r1;
r->p2link = r1->p2;
r1->p2 = r;
}
}
if(debug['R'])
print("\n%L %D\n", firstr->prog->lineno, &firstr->prog->from);
/*
* pass 2.5
* find looping structure
*/
for(r = firstr; r != R; r = r->link)
r->active = 0;
changer = 0;
loopit(firstr, npc);
if(debug['R'] && debug['v']) {
print("\nlooping structure:\n");
for(r = firstr; r != R; r = r->link) {
print("%ld:%P", r->loop, r->prog);
for(z=0; z<BITS; z++)
bit.b[z] = r->use1.b[z] |
r->use2.b[z] | r->set.b[z];
if(bany(&bit)) {
print("\t");
if(bany(&r->use1))
print(" u1=%B", r->use1);
if(bany(&r->use2))
print(" u2=%B", r->use2);
if(bany(&r->set))
print(" st=%B", r->set);
}
print("\n");
}
}
/*
* pass 3
* iterate propagating usage
* back until flow graph is complete
*/
loop1:
changer = 0;
for(r = firstr; r != R; r = r->link)
r->active = 0;
for(r = firstr; r != R; r = r->link)
if(r->prog->as == ARTS)
prop(r, zbits, zbits);
loop11:
/* pick up unreachable code */
i = 0;
for(r = firstr; r != R; r = r1) {
r1 = r->link;
if(r1 && r1->active && !r->active) {
prop(r, zbits, zbits);
i = 1;
}
}
if(i)
goto loop11;
if(changer)
goto loop1;
/*
* pass 4
* iterate propagating register/variable synchrony
* forward until graph is complete
*/
loop2:
changer = 0;
for(r = firstr; r != R; r = r->link)
r->active = 0;
synch(firstr, zbits);
if(changer)
goto loop2;
/*
* pass 5
* isolate regions
* calculate costs (paint1)
*/
r = firstr;
if(r) {
for(z=0; z<BITS; z++)
bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
~(externs.b[z] | params.b[z] | addrs.b[z]);
if(bany(&bit)) {
nearln = r->prog->lineno;
warn(Z, "used and not set: %B", bit);
if(debug['R'] && !debug['w'])
print("used and not set: %B\n", bit);
/*
* 68040 'feature':
* load of a denormalized fp will trap
*/
while(bany(&bit)) {
i = bnum(bit);
bit.b[i/32] &= ~(1L << (i%32));
v = var + i;
if(v->type == D_AUTO) {
r->set.b[i/32] |= (1L << (i%32));
if(typefd[v->etype])
addmove(r, i, NREG+NREG, 1);
}
}
}
}
if(debug['R'] && debug['v'])
print("\nprop structure:\n");
for(r = firstr; r != R; r = r->link) {
if(debug['R'] && debug['v'])
print("%P\n set = %B; rah = %B; cal = %B\n",
r->prog, r->set, r->refahead, r->calahead);
r->act = zbits;
}
rgp = region;
nregion = 0;
for(r = firstr; r != R; r = r->link) {
for(z=0; z<BITS; z++)
bit.b[z] = r->set.b[z] &
~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
if(bany(&bit)) {
nearln = r->prog->lineno;
warn(Z, "set and not used: %B", bit);
if(debug['R'])
print("set an not used: %B\n", bit);
excise(r);
}
for(z=0; z<BITS; z++)
bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
while(bany(&bit)) {
i = bnum(bit);
rgp->enter = r;
rgp->varno = i;
changer = 0;
changea = 0;
if(debug['R'] && debug['v'])
print("\n");
paint1(r, i);
bit.b[i/32] &= ~(1L<<(i%32));
if(changer <= 0 && changea <= 0) {
if(debug['R'])
print("%L$%d.%d: %B\n",
r->prog->lineno,
changer, changea, blsh(i));
continue;
}
rgp->costr = changer;
rgp->costa = changea;
nregion++;
if(nregion >= NRGN) {
warn(Z, "too many regions");
goto brk;
}
rgp++;
}
}
brk:
qsort(region, nregion, sizeof(region[0]), rcmp);
/*
* pass 6
* determine used registers (paint2)
* replace code (paint3)
*/
rgp = region;
for(i=0; i<nregion; i++) {
bit = blsh(rgp->varno);
vreg = paint2(rgp->enter, rgp->varno);
vreg = allreg(vreg, rgp);
if(debug['R'])
print("%L$%d.%d %R: %B\n",
rgp->enter->prog->lineno,
rgp->costr, rgp->costa,
rgp->regno,
bit);
if(rgp->regno != D_NONE)
paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
rgp++;
}
/*
* pass 7
* peep-hole on basic block
*/
if(!debug['R'] || debug['P'])
peep();
/*
* pass 8
* recalculate pc
*/
val = initpc;
for(r = firstr; r != R; r = r1) {
r->pc = val;
p = r->prog;
p1 = P;
r1 = r->link;
if(r1 != R)
p1 = r1->prog;
for(; p != p1; p = p->link) {
switch(p->as) {
default:
val++;
break;
case ANOP:
case ADATA:
case AGLOBL:
case ANAME:
case ASIGNAME:
break;
}
}
}
pc = val;
/*
* fix up branches
*/
if(debug['R'])
if(bany(&addrs))
print("addrs: %B\n", addrs);
r1 = 0; /* set */
for(r = firstr; r != R; r = r->link) {
p = r->prog;
if(p->to.type == D_BRANCH)
p->to.offset = r->s2->pc;
r1 = r;
}
/*
* last pass
* eliminate nops
* free aux structures
*/
for(p = firstr->prog; p != P; p = p->link){
while(p->link && p->link->as == ANOP)
p->link = p->link->link;
}
if(r1 != R) {
r1->link = freer;
freer = firstr;
}
}
/*
* add mov b,rn
* just after r
*/
void
addmove(Reg *r, int bn, int rn, int f)
{
Prog *p, *p1;
Var *v;
int badccr;
badccr = 0;
p = r->prog;
p1 = p->link;
if(p1)
switch(p1->as) {
case AMOVW:
if(p1->from.type == D_CCR)
p = p1;
break;
case ABEQ:
case ABNE:
case ABLE:
case ABLS:
case ABLT:
case ABMI:
case ABGE:
case ABPL:
case ABGT:
case ABHI:
case ABCC:
case ABCS:
p1 = prg();
p1->link = p->link;
p->link = p1;
p1->lineno = p->lineno;
p1->from.type = D_CCR;
p1->to.type = D_TOS;
p1->as = AMOVW;
p = p1;
badccr = 1;
}
p1 = prg();
p1->link = p->link;
p->link = p1;
p1->lineno = p->lineno;
v = var + bn;
p1->from.sym = v->sym;
p1->from.type = v->type;
p1->from.offset = v->offset;
p1->from.etype = v->etype;
p1->to.type = rn;
if(f) {
p1->to = p1->from;
p1->from = zprog.from;
p1->from.type = rn;
}
p1->as = opxt[OAS][v->etype];
if(badccr) {
p = p1;
p1 = prg();
p1->link = p->link;
p->link = p1;
p1->lineno = p->lineno;
p1->from.type = D_TOS;
p1->to.type = D_CCR;
p1->as = AMOVW;
}
if(debug['R'])
print("%P\t.a%P\n", p, p1);
}
Bits
mkvar(Adr *a, int as)
{
Var *v;
int i, t, z;
long o;
Bits bit;
Sym *s;
mvbits = 0;
t = a->type & D_MASK;
switch(t) {
default:
if(t >= D_R0 && t < D_R0+NREG) {
regbits |= RtoB(t-D_R0);
if(as == ADIVUL || as == ADIVSL)
regbits |= RtoB(t-D_R0+1);
}
if(t >= D_A0 && t < D_A0+NREG)
regbits |= AtoB(t-D_A0);
if(t >= D_F0 && t < D_F0+NREG)
regbits |= FtoB(t-D_F0);
goto none;
case D_EXTERN:
case D_STATIC:
case D_AUTO:
case D_PARAM:
break;
}
s = a->sym;
if(s == S)
goto none;
if((a->type & I_MASK) == I_ADDR)
mvbits |= B_ADDR;
switch(a->index & I_MASK) {
case I_INDEX1:
mvbits |= B_ADDR;
break;
case I_INDEX2:
case I_INDEX3:
mvbits |= B_INDIR;
break;
}
o = a->offset;
v = var;
for(i=0; i<nvar; i++) {
if(s == v->sym)
if(t == v->type)
if(o == v->offset)
goto out;
v++;
}
if(s)
if(s->name[0] == '.')
goto none;
if(nvar >= NVAR) {
if(debug['w'] > 1 && s)
warn(Z, "variable not optimized: %s", s->name);
goto none;
}
i = nvar;
nvar++;
v = &var[i];
v->sym = s;
v->offset = o;
v->etype = a->etype;
v->type = t;
if(debug['R'])
print("bit=%2d et=%2d %s (%p,%d,%ld)\n",
i, a->etype, s->name,
v->sym, v->type, v->offset);
out:
bit = blsh(i);
if(t == D_EXTERN || t == D_STATIC)
for(z=0; z<BITS; z++)
externs.b[z] |= bit.b[z];
if(t == D_PARAM)
for(z=0; z<BITS; z++)
params.b[z] |= bit.b[z];
if(a->etype != v->etype || !typechlpfd[a->etype])
for(z=0; z<BITS; z++)
addrs.b[z] |= bit.b[z]; /* funny punning */
return bit;
none:
return zbits;
}
void
prop(Reg *r, Bits ref, Bits cal)
{
Reg *r1, *r2;
int z;
for(r1 = r; r1 != R; r1 = r1->p1) {
for(z=0; z<BITS; z++) {
ref.b[z] |= r1->refahead.b[z];
if(ref.b[z] != r1->refahead.b[z]) {
r1->refahead.b[z] = ref.b[z];
changer++;
}
cal.b[z] |= r1->calahead.b[z];
if(cal.b[z] != r1->calahead.b[z]) {
r1->calahead.b[z] = cal.b[z];
changer++;
}
}
switch(r1->prog->as) {
case ABSR:
for(z=0; z<BITS; z++) {
cal.b[z] |= ref.b[z] | externs.b[z];
ref.b[z] = 0;
}
break;
case ATEXT:
for(z=0; z<BITS; z++) {
cal.b[z] = 0;
ref.b[z] = 0;
}
break;
case ARTS:
for(z=0; z<BITS; z++) {
cal.b[z] = externs.b[z];
ref.b[z] = 0;
}
}
for(z=0; z<BITS; z++) {
ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
r1->use1.b[z] | r1->use2.b[z];
cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
r1->refbehind.b[z] = ref.b[z];
r1->calbehind.b[z] = cal.b[z];
}
if(r1->active)
break;
r1->active = 1;
}
for(; r != r1; r = r->p1)
for(r2 = r->p2; r2 != R; r2 = r2->p2link)
prop(r2, r->refbehind, r->calbehind);
}
/*
* find looping structure
*
* 1) find reverse postordering
* 2) find approximate dominators,
* the actual dominators if the flow graph is reducible
* otherwise, dominators plus some other non-dominators.
* See Matthew S. Hecht and Jeffrey D. Ullman,
* "Analysis of a Simple Algorithm for Global Data Flow Problems",
* Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
* Oct. 1-3, 1973, pp. 207-217.
* 3) find all nodes with a predecessor dominated by the current node.
* such a node is a loop head.
* recursively, all preds with a greater rpo number are in the loop
*/
long
postorder(Reg *r, Reg **rpo2r, long n)
{
Reg *r1;
r->rpo = 1;
r1 = r->s1;
if(r1 && !r1->rpo)
n = postorder(r1, rpo2r, n);
r1 = r->s2;
if(r1 && !r1->rpo)
n = postorder(r1, rpo2r, n);
rpo2r[n] = r;
n++;
return n;
}
long
rpolca(long *idom, long rpo1, long rpo2)
{
long t;
if(rpo1 == -1)
return rpo2;
while(rpo1 != rpo2){
if(rpo1 > rpo2){
t = rpo2;
rpo2 = rpo1;
rpo1 = t;
}
while(rpo1 < rpo2){
t = idom[rpo2];
if(t >= rpo2)
fatal(Z, "bad idom");
rpo2 = t;
}
}
return rpo1;
}
int
doms(long *idom, long r, long s)
{
while(s > r)
s = idom[s];
return s == r;
}
int
loophead(long *idom, Reg *r)
{
long src;
src = r->rpo;
if(r->p1 != R && doms(idom, src, r->p1->rpo))
return 1;
for(r = r->p2; r != R; r = r->p2link)
if(doms(idom, src, r->rpo))
return 1;
return 0;
}
void
loopmark(Reg **rpo2r, long head, Reg *r)
{
if(r->rpo < head || r->active == head)
return;
r->active = head;
r->loop += LOOP;
if(r->p1 != R)
loopmark(rpo2r, head, r->p1);
for(r = r->p2; r != R; r = r->p2link)
loopmark(rpo2r, head, r);
}
void
loopit(Reg *r, long nr)
{
Reg *r1;
long i, d, me;
if(nr > maxnr) {
rpo2r = alloc(nr * sizeof(Reg*));
idom = alloc(nr * sizeof(long));
maxnr = nr;
}
d = postorder(r, rpo2r, 0);
if(d > nr)
fatal(Z, "too many reg nodes");
nr = d;
for(i = 0; i < nr / 2; i++){
r1 = rpo2r[i];
rpo2r[i] = rpo2r[nr - 1 - i];
rpo2r[nr - 1 - i] = r1;
}
for(i = 0; i < nr; i++)
rpo2r[i]->rpo = i;
idom[0] = 0;
for(i = 0; i < nr; i++){
r1 = rpo2r[i];
me = r1->rpo;
d = -1;
if(r1->p1 != R && r1->p1->rpo < me)
d = r1->p1->rpo;
for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
if(r1->rpo < me)
d = rpolca(idom, d, r1->rpo);
idom[i] = d;
}
for(i = 0; i < nr; i++){
r1 = rpo2r[i];
r1->loop++;
if(r1->p2 != R && loophead(idom, r1))
loopmark(rpo2r, i, r1);
}
}
void
synch(Reg *r, Bits dif)
{
Reg *r1;
int z;
for(r1 = r; r1 != R; r1 = r1->s1) {
for(z=0; z<BITS; z++) {
dif.b[z] = (dif.b[z] &
~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
r1->set.b[z] | r1->regdiff.b[z];
if(dif.b[z] != r1->regdiff.b[z]) {
r1->regdiff.b[z] = dif.b[z];
changer++;
}
}
if(r1->active)
break;
r1->active = 1;
for(z=0; z<BITS; z++)
dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
if(r1->s2 != R)
synch(r1->s2, dif);
}
}
ulong
allreg(ulong b, Rgn *r)
{
Var *v;
int i, j;
v = var + r->varno;
r->regno = D_NONE;
switch(v->etype) {
default:
diag(Z, "unknown etype");
break;
case TCHAR:
case TUCHAR:
case TSHORT:
case TUSHORT:
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
i = BtoR(~b);
j = BtoA(~b);
if(r->costa == r->costr)
if(i > j)
i = NREG;
if(j < NREG && r->costa > 0)
if(r->costa > r->costr || i >= NREG) {
r->regno = D_A0 + j;
return AtoB(j);
}
if(i < NREG && r->costr > 0) {
r->regno = D_R0 + i;
return RtoB(i);
}
break;
case TDOUBLE:
case TFLOAT:
i = BtoF(~b);
if(i < NREG) {
r->regno = D_F0 + i;
return FtoB(i);
}
break;
}
return 0;
}
void
paint1(Reg *r, int bn)
{
Reg *r1;
Prog *p;
int z;
ulong bb;
int x;
z = bn/32;
bb = 1L<<(bn%32);
if(r->act.b[z] & bb)
return;
for(;;) {
if(!(r->refbehind.b[z] & bb))
break;
r1 = r->p1;
if(r1 == R)
break;
if(!(r1->refahead.b[z] & bb))
break;
if(r1->act.b[z] & bb)
break;
r = r1;
}
if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
changer -= CLOAD * r->loop;
changea -= CLOAD * r->loop;
if(debug['R'] && debug['v'])
print("%ld%P\tld %B $%d.%d\n", r->loop,
r->prog, blsh(bn), changer, changea);
}
for(;;) {
r->act.b[z] |= bb;
p = r->prog;
if(r->use1.b[z] & bb) {
changer += CREF * r->loop;
changea += CREF * r->loop;
x = p->from.index;
if(x == D_NONE) {
switch(p->as) {
default:
changea = -CINF;
case AADDL:
case ASUBL:
case AMOVL:
case ACMPL:
break;
}
} else {
changer += (CXREF-CREF) * r->loop;
if(x != (I_INDEX3|D_NONE))
changer = -CINF;
if((x&I_MASK) == I_INDEX1)
changea = -CINF;
}
if(p->as == AMOVL) {
x = p->to.type;
if(x >= D_R0 && x < D_R0+NREG)
changer += r->loop;
if(x >= D_A0 && x < D_A0+NREG)
changea += r->loop;
}
if(debug['R'] && debug['v'])
print("%ld%P\tu1 %B $%d.%d\n", r->loop,
p, blsh(bn), changer, changea);
}
if((r->use2.b[z]|r->set.b[z]) & bb) {
changer += CREF * r->loop;
changea += CREF * r->loop;
x = p->to.index;
if(x == D_NONE)
switch(p->as) {
default:
changea = -CINF;
break;
case AMOVL:
case AADDL:
case ACMPL:
case ASUBL:
case ACLRL: /* can be faked */
case ATSTL: /* can be faked */
break;
}
else {
changer += (CXREF-CREF) * r->loop;
if(x != (I_INDEX3|D_NONE))
changer = -CINF;
if((x&I_MASK) == I_INDEX1)
changea = -CINF;
}
if(p->as == AMOVL) {
x = p->from.type;
if(x >= D_R0 && x < D_R0+NREG)
changer += r->loop;
if(x >= D_A0 && x < D_A0+NREG)
changea += r->loop;
}
if(debug['R'] && debug['v'])
print("%ld%P\tu2 %B $%d.%d\n", r->loop,
p, blsh(bn), changer, changea);
}
if(STORE(r) & r->regdiff.b[z] & bb) {
changer -= CLOAD * r->loop;
changea -= CLOAD * r->loop;
if(debug['R'] && debug['v'])
print("%ld%P\tst %B $%d.%d\n", r->loop,
p, blsh(bn), changer, changea);
}
if(r->refbehind.b[z] & bb)
for(r1 = r->p2; r1 != R; r1 = r1->p2link)
if(r1->refahead.b[z] & bb)
paint1(r1, bn);
if(!(r->refahead.b[z] & bb))
break;
r1 = r->s2;
if(r1 != R)
if(r1->refbehind.b[z] & bb)
paint1(r1, bn);
r = r->s1;
if(r == R)
break;
if(r->act.b[z] & bb)
break;
if(!(r->refbehind.b[z] & bb))
break;
}
}
ulong
paint2(Reg *r, int bn)
{
Reg *r1;
int z;
ulong bb, vreg;
z = bn/32;
bb = 1L << (bn%32);
vreg = regbits;
if(!(r->act.b[z] & bb))
return vreg;
for(;;) {
if(!(r->refbehind.b[z] & bb))
break;
r1 = r->p1;
if(r1 == R)
break;
if(!(r1->refahead.b[z] & bb))
break;
if(!(r1->act.b[z] & bb))
break;
r = r1;
}
for(;;) {
r->act.b[z] &= ~bb;
vreg |= r->regu;
if(r->refbehind.b[z] & bb)
for(r1 = r->p2; r1 != R; r1 = r1->p2link)
if(r1->refahead.b[z] & bb)
vreg |= paint2(r1, bn);
if(!(r->refahead.b[z] & bb))
break;
r1 = r->s2;
if(r1 != R)
if(r1->refbehind.b[z] & bb)
vreg |= paint2(r1, bn);
r = r->s1;
if(r == R)
break;
if(!(r->act.b[z] & bb))
break;
if(!(r->refbehind.b[z] & bb))
break;
}
return vreg;
}
void
paint3(Reg *r, int bn, ulong rb, int rn)
{
Reg *r1;
Prog *p;
int z;
ulong bb;
z = bn/32;
bb = 1L << (bn%32);
if(r->act.b[z] & bb)
return;
for(;;) {
if(!(r->refbehind.b[z] & bb))
break;
r1 = r->p1;
if(r1 == R)
break;
if(!(r1->refahead.b[z] & bb))
break;
if(r1->act.b[z] & bb)
break;
r = r1;
}
if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
addmove(r, bn, rn, 0);
for(;;) {
r->act.b[z] |= bb;
p = r->prog;
if(r->use1.b[z] & bb) {
if(debug['R'])
print("%P", p);
addreg(&p->from, rn);
if(debug['R'])
print("\t.c%P\n", p);
}
if((r->use2.b[z]|r->set.b[z]) & bb) {
if(debug['R'])
print("%P", p);
addreg(&p->to, rn);
if(debug['R'])
print("\t.c%P\n", p);
}
if(STORE(r) & r->regdiff.b[z] & bb)
addmove(r, bn, rn, 1);
r->regu |= rb;
if(r->refbehind.b[z] & bb)
for(r1 = r->p2; r1 != R; r1 = r1->p2link)
if(r1->refahead.b[z] & bb)
paint3(r1, bn, rb, rn);
if(!(r->refahead.b[z] & bb))
break;
r1 = r->s2;
if(r1 != R)
if(r1->refbehind.b[z] & bb)
paint3(r1, bn, rb, rn);
r = r->s1;
if(r == R)
break;
if(r->act.b[z] & bb)
break;
if(!(r->refbehind.b[z] & bb))
break;
}
}
void
addreg(Adr *a, int rn)
{
int x;
a->sym = 0;
x = a->index;
if(rn >= D_R0 && rn < D_R0+NREG)
goto addr;
if(x == (I_INDEX3|D_NONE)) {
a->type = rn | I_INDIR;
a->index = D_NONE;
a->offset = a->displace;
a->displace = 0;
return;
}
if(x != D_NONE) {
a->type = rn | I_INDIR;
a->index += I_INDEX1 - I_INDEX2;
a->offset = a->displace;
a->displace = 0;
return;
}
a->type = rn | (a->type & I_INDIR);
return;
addr:
if(x == (I_INDEX3|D_NONE)) {
a->type = D_NONE|I_INDIR;
a->index += I_INDEX1 + rn - D_NONE - I_INDEX3;
a->scale = 4; /* .L*1 */
a->offset = a->displace;
a->displace = 0;
return;
}
a->type = rn | (a->type & I_INDIR);
}
/*
* bit reg
* 0-7 R0-R7
* 8-15 A0-A7
* 16-23 F0-F7
*/
ulong
RtoB(int r)
{
if(r < 0 || r >= NREG)
return 0;
return 1L << (r + 0);
}
int
BtoR(ulong b)
{
b &= 0x0000ffL;
if(b == 0)
return NREG;
return bitno(b) - 0;
}
ulong
AtoB(int a)
{
if(a < 0 || a >= NREG)
return 0;
return 1L << (a + NREG);
}
int
BtoA(ulong b)
{
b &= 0x00ff00L;
if(b == 0)
return NREG;
return bitno(b) - NREG;
}
ulong
FtoB(int f)
{
if(f < 0 || f >= NREG)
return 0;
return 1L << (f + NREG+NREG);
}
int
BtoF(ulong b)
{
b &= 0xff0000L;
if(b == 0)
return NREG;
return bitno(b) - NREG-NREG;
}