int is used all over the place for temporaries, maybe this should be changed, I don't know. Another thing to consider is that temporaries are currently on 12 bits (and will be on 29 or 30 bits in the future), so int will always be safe to store them. We just loose the free invariant of non-negativity.
173 lines
3.4 KiB
C
173 lines
3.4 KiB
C
#include "all.h"
|
|
|
|
void
|
|
liveon(BSet *v, Blk *b, Blk *s)
|
|
{
|
|
Phi *p;
|
|
uint a;
|
|
|
|
bscopy(v, s->in);
|
|
for (p=s->phi; p; p=p->link) {
|
|
bsclr(v, p->to.val);
|
|
for (a=0; a<p->narg; a++)
|
|
if (p->blk[a] == b)
|
|
if (rtype(p->arg[a]) == RTmp)
|
|
bsset(v, p->arg[a].val);
|
|
}
|
|
}
|
|
|
|
static int
|
|
phitmp(int t, Tmp *tmp)
|
|
{
|
|
int tp;
|
|
|
|
tp = tmp[t].phi;
|
|
return tp ? tp : t;
|
|
}
|
|
|
|
static void
|
|
phifix(int t1, short *phi, Tmp *tmp)
|
|
{
|
|
int t, t2;
|
|
|
|
/* detect temporaries arguments
|
|
* of the same phi node that
|
|
* interfere and separate them
|
|
*/
|
|
t = phitmp(t1, tmp);
|
|
t2 = phi[t];
|
|
if (t2 && t2 != t1) {
|
|
if (t != t1) {
|
|
tmp[t1].phi = t1;
|
|
t = t1;
|
|
} else {
|
|
tmp[t2].phi = t2;
|
|
phi[t2] = t2;
|
|
}
|
|
}
|
|
phi[t] = t1;
|
|
}
|
|
|
|
static void
|
|
bset(Ref r, Blk *b, int *nlv, short *phi, Tmp *tmp)
|
|
{
|
|
|
|
if (rtype(r) != RTmp)
|
|
return;
|
|
bsset(b->gen, r.val);
|
|
phifix(r.val, phi, tmp);
|
|
if (!bshas(b->in, r.val)) {
|
|
nlv[KBASE(tmp[r.val].cls)]++;
|
|
bsset(b->in, r.val);
|
|
}
|
|
}
|
|
|
|
/* liveness analysis
|
|
* requires rpo computation
|
|
*/
|
|
void
|
|
filllive(Fn *f)
|
|
{
|
|
Blk *b;
|
|
Ins *i;
|
|
int k, t, m[2], n, chg, nlv[2];
|
|
short *phi;
|
|
BSet u[1], v[1];
|
|
Mem *ma;
|
|
|
|
bsinit(u, f->ntmp);
|
|
bsinit(v, f->ntmp);
|
|
phi = emalloc(f->ntmp * sizeof phi[0]);
|
|
for (b=f->start; b; b=b->link) {
|
|
bsinit(b->in, f->ntmp);
|
|
bsinit(b->out, f->ntmp);
|
|
bsinit(b->gen, f->ntmp);
|
|
}
|
|
chg = 1;
|
|
Again:
|
|
for (n=f->nblk-1; n>=0; n--) {
|
|
b = f->rpo[n];
|
|
|
|
bscopy(u, b->out);
|
|
if (b->s1) {
|
|
liveon(v, b, b->s1);
|
|
bsunion(b->out, v);
|
|
}
|
|
if (b->s2) {
|
|
liveon(v, b, b->s2);
|
|
bsunion(b->out, v);
|
|
}
|
|
chg |= !bsequal(b->out, u);
|
|
|
|
memset(phi, 0, f->ntmp * sizeof phi[0]);
|
|
memset(nlv, 0, sizeof nlv);
|
|
bscopy(b->in, b->out);
|
|
for (t=0; bsiter(b->in, &t); t++) {
|
|
phifix(t, phi, f->tmp);
|
|
nlv[KBASE(f->tmp[t].cls)]++;
|
|
}
|
|
if (rtype(b->jmp.arg) == RACall) {
|
|
assert(bscount(b->in) == 0 && nlv[0] == 0 && nlv[1] == 0);
|
|
b->in->t[0] |= retregs(b->jmp.arg, nlv);
|
|
} else
|
|
bset(b->jmp.arg, b, nlv, phi, f->tmp);
|
|
for (k=0; k<2; k++)
|
|
b->nlive[k] = nlv[k];
|
|
for (i=&b->ins[b->nins]; i!=b->ins;) {
|
|
if ((--i)->op == OCall && rtype(i->arg[1]) == RACall) {
|
|
b->in->t[0] &= ~retregs(i->arg[1], m);
|
|
for (k=0; k<2; k++)
|
|
nlv[k] -= m[k];
|
|
if (nlv[0] + NISave > b->nlive[0])
|
|
b->nlive[0] = nlv[0] + NISave;
|
|
if (nlv[1] + NFSave > b->nlive[1])
|
|
b->nlive[1] = nlv[1] + NFSave;
|
|
b->in->t[0] |= argregs(i->arg[1], m);
|
|
for (k=0; k<2; k++)
|
|
nlv[k] += m[k];
|
|
}
|
|
if (!req(i->to, R)) {
|
|
assert(rtype(i->to) == RTmp);
|
|
t = i->to.val;
|
|
if (bshas(b->in, i->to.val))
|
|
nlv[KBASE(f->tmp[t].cls)]--;
|
|
bsset(b->gen, t);
|
|
bsclr(b->in, t);
|
|
phi[phitmp(t, f->tmp)] = 0;
|
|
}
|
|
for (k=0; k<2; k++)
|
|
switch (rtype(i->arg[k])) {
|
|
case RAMem:
|
|
ma = &f->mem[i->arg[k].val & AMask];
|
|
bset(ma->base, b, nlv, phi, f->tmp);
|
|
bset(ma->index, b, nlv, phi, f->tmp);
|
|
break;
|
|
default:
|
|
bset(i->arg[k], b, nlv, phi, f->tmp);
|
|
break;
|
|
}
|
|
for (k=0; k<2; k++)
|
|
if (nlv[k] > b->nlive[k])
|
|
b->nlive[k] = nlv[k];
|
|
}
|
|
}
|
|
if (chg) {
|
|
chg = 0;
|
|
goto Again;
|
|
}
|
|
free(phi);
|
|
|
|
if (debug['L']) {
|
|
fprintf(stderr, "\n> Liveness analysis:\n");
|
|
for (b=f->start; b; b=b->link) {
|
|
fprintf(stderr, "\t%-10sin: ", b->name);
|
|
dumpts(b->in, f->tmp, stderr);
|
|
fprintf(stderr, "\t out: ");
|
|
dumpts(b->out, f->tmp, stderr);
|
|
fprintf(stderr, "\t gen: ");
|
|
dumpts(b->gen, f->tmp, stderr);
|
|
fprintf(stderr, "\t live: ");
|
|
fprintf(stderr, "%d %d\n", b->nlive[0], b->nlive[1]);
|
|
}
|
|
}
|
|
}
|