mirror of
git://c9x.me/qbe.git
synced 2026-04-05 18:09:47 +00:00
store register usage of ret instructions (abi fuzz)
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.
This commit is contained in:
parent
5ad3eaa75a
commit
337b10f6ed
36
lisc/isel.c
36
lisc/isel.c
@ -434,23 +434,26 @@ blit(Ref rstk, uint soff, Ref rsrc, uint sz, Fn *fn)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
retr(Ref reg[2], AClass *aret)
|
||||
{
|
||||
static int retreg[2][2] = {{RAX, RDX}, {XMM0, XMM0+1}};
|
||||
int n, k, nr[2];
|
||||
int n, k, ca, nr[2];
|
||||
|
||||
nr[0] = nr[1] = 0;
|
||||
ca = 0;
|
||||
for (n=0; aret->cls[n]>=0 && n<2; n++) {
|
||||
k = KBASE(aret->cls[n]);
|
||||
reg[n] = TMP(retreg[k][nr[k]++]);
|
||||
ca += 1 << (2 * k);
|
||||
}
|
||||
return ca;
|
||||
}
|
||||
|
||||
static void
|
||||
selret(Blk *b, Fn *fn)
|
||||
{
|
||||
int j, k;
|
||||
int j, k, ca;
|
||||
Ref r, r0, reg[2];
|
||||
AClass aret;
|
||||
|
||||
@ -460,7 +463,6 @@ selret(Blk *b, Fn *fn)
|
||||
return;
|
||||
|
||||
r0 = b->jmp.arg;
|
||||
b->jmp.arg = R;
|
||||
b->jmp.type = JRet0;
|
||||
|
||||
if (j == JRetc) {
|
||||
@ -470,8 +472,9 @@ selret(Blk *b, Fn *fn)
|
||||
emit(OCopy, Kl, TMP(RAX), fn->retr, R);
|
||||
chuse(fn->retr, +1, fn);
|
||||
blit(fn->retr, 0, r0, aret.size, fn);
|
||||
ca = 1;
|
||||
} else {
|
||||
retr(reg, &aret);
|
||||
ca = retr(reg, &aret);
|
||||
if (aret.size > 8) {
|
||||
r = newtmp("abi", Kl, fn);
|
||||
emit(OLoad, Kl, reg[1], r, R);
|
||||
@ -482,11 +485,16 @@ selret(Blk *b, Fn *fn)
|
||||
}
|
||||
} else {
|
||||
k = j - JRetw;
|
||||
if (KBASE(k) == 0)
|
||||
if (KBASE(k) == 0) {
|
||||
emit(OCopy, k, TMP(RAX), r0, R);
|
||||
else
|
||||
ca = 1;
|
||||
} else {
|
||||
emit(OCopy, k, TMP(XMM0), r0, R);
|
||||
ca = 1 << 2;
|
||||
}
|
||||
}
|
||||
|
||||
b->jmp.arg = CALL(ca);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -607,14 +615,15 @@ MAKESURE(rsave_has_correct_size, sizeof rsave == NRSave * sizeof(int));
|
||||
MAKESURE(rclob_has_correct_size, sizeof rclob == NRClob * sizeof(int));
|
||||
|
||||
bits
|
||||
calldef(Ins i, int p[2])
|
||||
retregs(Ref r, int p[2])
|
||||
{
|
||||
bits b;
|
||||
int ni, nf;
|
||||
|
||||
assert(rtype(r) == RACall);
|
||||
b = 0;
|
||||
ni = i.arg[1].val & 3;
|
||||
nf = (i.arg[1].val >> 2) & 3;
|
||||
ni = r.val & 3;
|
||||
nf = (r.val >> 2) & 3;
|
||||
if (ni >= 1)
|
||||
b |= BIT(RAX);
|
||||
if (ni >= 2)
|
||||
@ -631,14 +640,15 @@ calldef(Ins i, int p[2])
|
||||
}
|
||||
|
||||
bits
|
||||
calluse(Ins i, int p[2])
|
||||
argregs(Ref r, int p[2])
|
||||
{
|
||||
bits b;
|
||||
int j, ni, nf;
|
||||
|
||||
assert(rtype(r) == RACall);
|
||||
b = 0;
|
||||
ni = (i.arg[1].val >> 4) & 15;
|
||||
nf = (i.arg[1].val >> 8) & 15;
|
||||
ni = (r.val >> 4) & 15;
|
||||
nf = (r.val >> 8) & 15;
|
||||
for (j=0; j<ni; j++)
|
||||
b |= BIT(rsave[j]);
|
||||
for (j=0; j<nf; j++)
|
||||
|
||||
@ -536,8 +536,8 @@ void filllive(Fn *);
|
||||
/* isel.c */
|
||||
extern int rsave[/* NRSave */];
|
||||
extern int rclob[/* NRClob */];
|
||||
bits calldef(Ins, int[2]);
|
||||
bits calluse(Ins, int[2]);
|
||||
bits retregs(Ref, int[2]);
|
||||
bits argregs(Ref, int[2]);
|
||||
void isel(Fn *);
|
||||
|
||||
/* spill.c */
|
||||
|
||||
10
lisc/live.c
10
lisc/live.c
@ -107,19 +107,23 @@ Again:
|
||||
phifix(t, phi, f->tmp);
|
||||
nlv[KBASE(f->tmp[t].cls)]++;
|
||||
}
|
||||
bset(b->jmp.arg, b, nlv, phi, f->tmp);
|
||||
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] &= ~calldef(*i, m);
|
||||
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] |= calluse(*i, m);
|
||||
b->in->t[0] |= argregs(i->arg[1], m);
|
||||
for (k=0; k<2; k++)
|
||||
nlv[k] += m[k];
|
||||
}
|
||||
|
||||
@ -1055,7 +1055,7 @@ printfn(Fn *fn, FILE *f)
|
||||
case JRetd:
|
||||
case JRetc:
|
||||
fprintf(f, "\t%s", jtoa[b->jmp.type]);
|
||||
if (b->jmp.type != JRet0) {
|
||||
if (b->jmp.type != JRet0 || !req(b->jmp.arg, R)) {
|
||||
fprintf(f, " ");
|
||||
printref(b->jmp.arg, fn, f);
|
||||
}
|
||||
|
||||
11
lisc/rega.c
11
lisc/rega.c
@ -294,7 +294,7 @@ dopm(Blk *b, Ins *i, RMap *m)
|
||||
} while (i != b->ins && regcpy(i-1));
|
||||
assert(m0.n <= m->n);
|
||||
if (i != b->ins && (i-1)->op == OCall) {
|
||||
def = calldef(*(i-1), 0);
|
||||
def = retregs((i-1)->arg[1], 0);
|
||||
for (r=0; r<NRSave; r++)
|
||||
if (!(BIT(rsave[r]) & def))
|
||||
move(rsave[r], R, m);
|
||||
@ -364,10 +364,17 @@ doblk(Blk *b, RMap *cur)
|
||||
|
||||
if (rtype(b->jmp.arg) == RTmp)
|
||||
b->jmp.arg = ralloc(cur, b->jmp.arg.val);
|
||||
else if (rtype(b->jmp.arg) == RACall) {
|
||||
/* add return registers */
|
||||
rs = retregs(b->jmp.arg, 0);
|
||||
for (r=0; rs; rs/=2, r++)
|
||||
if (rs & 1)
|
||||
radd(cur, r, r);
|
||||
}
|
||||
for (i=&b->ins[b->nins]; i!=b->ins;) {
|
||||
switch ((--i)->op) {
|
||||
case OCall:
|
||||
rs = calluse(*i, 0);
|
||||
rs = argregs(i->arg[1], 0);
|
||||
for (r=0; r<NRSave; r++)
|
||||
if (!(BIT(rsave[r]) & rs))
|
||||
rfree(cur, rsave[r]);
|
||||
|
||||
10
lisc/spill.c
10
lisc/spill.c
@ -290,11 +290,11 @@ dopm(Blk *b, Ins *i, BSet *v)
|
||||
} while (i != b->ins && regcpy(i-1));
|
||||
bscopy(u, v);
|
||||
if (i != b->ins && (i-1)->op == OCall) {
|
||||
v->t[0] &= ~calldef(*(i-1), 0);
|
||||
v->t[0] &= ~retregs((i-1)->arg[1], 0);
|
||||
limit2(v, NISave, NFSave, 0);
|
||||
for (r=0, n=0; n<NRSave; n++)
|
||||
r |= BIT(rsave[n]);
|
||||
v->t[0] |= calluse(*(i-1), 0);
|
||||
v->t[0] |= argregs((i-1)->arg[1], 0);
|
||||
} else {
|
||||
limit2(v, 0, 0, 0);
|
||||
r = v->t[0];
|
||||
@ -365,6 +365,7 @@ spill(Fn *fn)
|
||||
if (s2 && s2->id <= n)
|
||||
if (!hd || s2->id >= hd->id)
|
||||
hd = s2;
|
||||
r = 0;
|
||||
bszero(v);
|
||||
if (hd) {
|
||||
/* back-edge */
|
||||
@ -393,12 +394,15 @@ spill(Fn *fn)
|
||||
bsunion(v, u);
|
||||
}
|
||||
limit2(v, 0, 0, w);
|
||||
} else if (rtype(b->jmp.arg) == RACall) {
|
||||
/* return */
|
||||
r = retregs(b->jmp.arg, 0);
|
||||
v->t[0] |= r;
|
||||
}
|
||||
bscopy(b->out, v);
|
||||
|
||||
/* 2. process the block instructions */
|
||||
curi = &insb[NIns];
|
||||
r = 0;
|
||||
for (i=&b->ins[b->nins]; i!=b->ins;) {
|
||||
i--;
|
||||
if (regcpy(i)) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user