qbe/live.c
Quentin Carbonneaux c9f04db881 refine assertion in liveness analysis
We were redundantly checking cardinality in a
way that prevented fp regs from ever being
globally live.  We now check that the live
regs after a return are exactly the globally
live ones.
2022-06-14 09:11:44 +02:00

144 lines
3 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)
if (rtype(p->to) == RTmp)
bsclr(v, p->to.val);
for (p=s->phi; p; p=p->link)
for (a=0; a<p->narg; a++)
if (p->blk[a] == b)
if (rtype(p->arg[a]) == RTmp) {
bsset(v, p->arg[a].val);
bsset(b->gen, p->arg[a].val);
}
}
static void
bset(Ref r, Blk *b, int *nlv, Tmp *tmp)
{
if (rtype(r) != RTmp)
return;
bsset(b->gen, r.val);
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];
BSet u[1], v[1];
Mem *ma;
bsinit(u, f->ntmp);
bsinit(v, f->ntmp);
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(nlv, 0, sizeof nlv);
b->out->t[0] |= T.rglob;
bscopy(b->in, b->out);
for (t=0; bsiter(b->in, &t); t++)
nlv[KBASE(f->tmp[t].cls)]++;
if (rtype(b->jmp.arg) == RCall) {
assert((int)bscount(b->in) == T.nrglob &&
b->in->t[0] == T.rglob);
b->in->t[0] |= T.retregs(b->jmp.arg, nlv);
} else
bset(b->jmp.arg, b, nlv, 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]) == RCall) {
b->in->t[0] &= ~T.retregs(i->arg[1], m);
for (k=0; k<2; k++) {
nlv[k] -= m[k];
/* caller-save registers are used
* by the callee, in that sense,
* right in the middle of the call,
* they are live: */
nlv[k] += T.nrsave[k];
if (nlv[k] > b->nlive[k])
b->nlive[k] = nlv[k];
}
b->in->t[0] |= T.argregs(i->arg[1], m);
for (k=0; k<2; k++) {
nlv[k] -= T.nrsave[k];
nlv[k] += m[k];
}
}
if (!req(i->to, R)) {
assert(rtype(i->to) == RTmp);
t = i->to.val;
if (bshas(b->in, t))
nlv[KBASE(f->tmp[t].cls)]--;
bsset(b->gen, t);
bsclr(b->in, t);
}
for (k=0; k<2; k++)
switch (rtype(i->arg[k])) {
case RMem:
ma = &f->mem[i->arg[k].val];
bset(ma->base, b, nlv, f->tmp);
bset(ma->index, b, nlv, f->tmp);
break;
default:
bset(i->arg[k], b, nlv, 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;
}
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]);
}
}
}