mirror of
git://c9x.me/qbe.git
synced 2026-04-05 18:09:47 +00:00
So far I was ignoring register uses of return instructions
and it was working because at most one register could be
returned. Now that more complex returns are supported it
is necessary to keep track of the registers used by
returns.
The abi fuzzer triggered an assertion failure in the
register allocator with the following IL:
R1 =l load [%t16]
R3 =l load [8 + %t16]
ret
The regalloc would use R1 for %t16, and then a (nice)
assertion realized the inconsistent state because R1
could only be def'd by an assignment to %t16.
175 lines
3.5 KiB
C
175 lines
3.5 KiB
C
#include "lisc.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; t<f->ntmp; t++)
|
|
if (bshas(b->in, 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]);
|
|
}
|
|
}
|
|
}
|