diff options
author | Quentin Carbonneaux <quentin.carbonneaux@yale.edu> | 2016-03-22 11:53:57 -0400 |
---|---|---|
committer | Quentin Carbonneaux <quentin.carbonneaux@yale.edu> | 2016-03-22 11:53:57 -0400 |
commit | 337b10f6edc4d56cbf126255b3e63e6e0b7c8530 (patch) | |
tree | da84c497678c8453bfa4d127c26aa8496b974947 /lisc | |
parent | 5ad3eaa75a19db2c38406b9be693d60f624cb305 (diff) | |
download | roux-337b10f6edc4d56cbf126255b3e63e6e0b7c8530.tar.gz |
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.
Diffstat (limited to 'lisc')
-rw-r--r-- | lisc/isel.c | 36 | ||||
-rw-r--r-- | lisc/lisc.h | 4 | ||||
-rw-r--r-- | lisc/live.c | 10 | ||||
-rw-r--r-- | lisc/parse.c | 2 | ||||
-rw-r--r-- | lisc/rega.c | 11 | ||||
-rw-r--r-- | lisc/spill.c | 10 |
6 files changed, 49 insertions, 24 deletions
diff --git a/lisc/isel.c b/lisc/isel.c index 42388af..2235cff 100644 --- a/lisc/isel.c +++ b/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++) diff --git a/lisc/lisc.h b/lisc/lisc.h index c6405ca..41be0ad 100644 --- a/lisc/lisc.h +++ b/lisc/lisc.h @@ -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 */ diff --git a/lisc/live.c b/lisc/live.c index 7efcfbf..43ceed9 100644 --- a/lisc/live.c +++ b/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]; } diff --git a/lisc/parse.c b/lisc/parse.c index aa7bc27..49595c4 100644 --- a/lisc/parse.c +++ b/lisc/parse.c @@ -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); } diff --git a/lisc/rega.c b/lisc/rega.c index 6c01dbb..ead2806 100644 --- a/lisc/rega.c +++ b/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]); diff --git a/lisc/spill.c b/lisc/spill.c index 2d509a0..33392a3 100644 --- a/lisc/spill.c +++ b/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)) { |