diff options
author | Quentin Carbonneaux <quentin.carbonneaux@yale.edu> | 2016-03-17 13:41:12 -0400 |
---|---|---|
committer | Quentin Carbonneaux <quentin.carbonneaux@yale.edu> | 2016-03-17 13:41:12 -0400 |
commit | 240cfcd5cdda9301457867f9d26edcd0cf272b24 (patch) | |
tree | 83cf01d43ad41163c96c34f16f2d24a4e8f9eff9 /lisc/isel.c | |
parent | 2889d44f24d8017f527f6f5aa1163065cc57e994 (diff) | |
download | roux-240cfcd5cdda9301457867f9d26edcd0cf272b24.tar.gz |
support return of structs
Diffstat (limited to 'lisc/isel.c')
-rw-r--r-- | lisc/isel.c | 253 |
1 files changed, 148 insertions, 105 deletions
diff --git a/lisc/isel.c b/lisc/isel.c index 8752012..ef9cbb7 100644 --- a/lisc/isel.c +++ b/lisc/isel.c @@ -140,7 +140,7 @@ fixarg(Ref *r, int k, int phi, Fn *fn) * a 32bit signed integer into a * long temporary */ - r1 = newtmp("isel", fn); + r1 = newtmp("isel", Kl, fn); emit(OCopy, Kl, r1, r0, R); } else if (s != -1) { @@ -148,7 +148,7 @@ fixarg(Ref *r, int k, int phi, Fn *fn) * temporaries right before the * instruction */ - r1 = newtmp("isel", fn); + r1 = newtmp("isel", Kl, fn); emit(OAddr, Kl, r1, SLOT(s), R); } *r = r1; @@ -233,7 +233,7 @@ sel(Ins i, ANum *an, Fn *fn) /* immediates not allowed for * divisions in x86 */ - r0 = newtmp("isel", fn); + r0 = newtmp("isel", k, fn); } else r0 = i.arg[1]; if (i.op == ODiv || i.op == ORem) { @@ -310,11 +310,11 @@ Emit: emit(OAlloc, Kl, i.to, getcon(val, fn), R); } else { /* r0 = (i.arg[0] + 15) & -16 */ - r0 = newtmp("isel", fn); - r1 = newtmp("isel", fn); + r0 = newtmp("isel", Kl, fn); + r1 = newtmp("isel", Kl, fn); emit(OSAlloc, Kl, i.to, r0, R); - emit(OAnd, 1, r0, r1, getcon(-16, fn)); - emit(OAdd, 1, r1, i.arg[0], getcon(15, fn)); + emit(OAnd, Kl, r0, r1, getcon(-16, fn)); + emit(OAdd, Kl, r1, i.arg[0], getcon(15, fn)); } break; default: @@ -352,33 +352,134 @@ flagi(Ins *i0, Ins *i) return 0; } +struct AClass { + int inmem; + int align; + uint size; + int cls[2]; +}; + static void -seljmp(Blk *b, Fn *fn) +aclass(AClass *a, Typ *t) { - Ref r; - int c, k; - Ins *fi; + int e, s, n, cls; + uint sz, al; - switch (b->jmp.type) { - default: + sz = t->size; + al = 1u << t->align; + + /* the ABI requires sizes to be rounded + * up to the nearest multiple of 8, moreover + * it makes it easy load and store structures + * in registers + */ + if (al < 8) + al = 8; + sz = (sz + al-1) & -al; + + a->size = sz; + a->align = t->align; + + if (t->dark || sz > 16) { + /* large or unaligned structures are + * required to be passed in memory + */ + a->inmem = 1; + return; + } + + for (e=0, s=0; e<2; e++) { + cls = -1; + for (n=0; n<8 && t->seg[s].len; s++) { + if (t->seg[s].flt) { + if (cls == -1) + cls = Kd; + } else + cls = Kl; + n += t->seg[s].len; + } + assert(n <= 8); + a->cls[e] = cls; + } +} + +static void +blit(Ref rstk, uint soff, Ref rsrc, uint sz, Fn *fn) +{ + Ref r, r1; + uint boff; + + /* it's an impolite blit, we might go across the end + * of the source object a little bit... */ + for (boff=0; sz>0; sz-=8, soff+=8, boff+=8) { + r = newtmp("abi", Kl, fn); + r1 = newtmp("abi", Kl, fn); + emit(OStorel, 0, R, r, r1); + emit(OAdd, Kl, r1, rstk, getcon(soff, fn)); + r1 = newtmp("abi", Kl, fn); + emit(OLoad, Kl, r, r1, R); + emit(OAdd, Kl, r1, rsrc, getcon(boff, fn)); + chuse(rsrc, +1, fn); + chuse(rstk, +1, fn); + } +} + +static void +selret(Blk *b, Fn *fn) +{ + static int retreg[2][2] = {{RAX, RDX}, {XMM0, XMM0+1}}; + int j, n, k, nr[2]; + Ref r, r0, reg[2]; + AClass a; + + j = b->jmp.type; + + if (!isret(j) || j == JRet0) return; - case JRetc: - assert(!"retc todo"); - case JRetw: - case JRetl: - case JRets: - case JRetd: - k = b->jmp.type - JRetw; + + r0 = b->jmp.arg; + b->jmp.arg = R; + b->jmp.type = JRet0; + + if (j == JRetc) { + aclass(&a, &typ[fn->retty]); b->jmp.type = JRet0; - r = b->jmp.arg; - b->jmp.arg = R; + if (a.inmem) { + assert(rtype(fn->retr) == RTmp); + emit(OCopy, Kl, TMP(RAX), fn->retr, R); + blit(fn->retr, 0, r0, a.size, fn); + } else { + nr[0] = nr[1] = 0; + for (n=0; n<2; n++) { + k = KBASE(a.cls[n]); + reg[n] = TMP(retreg[k][nr[k]++]); + } + if (a.size > 8) { + r = newtmp("abi", Kl, fn); + emit(OLoad, Kl, reg[1], r, R); + emit(OAdd, Kl, r, r0, getcon(8, fn)); + } + emit(OLoad, Kl, reg[0], r0, R); + } + } else { + k = j - JRetw; if (KBASE(k) == 0) - emit(OCopy, k, TMP(RAX), r, R); + emit(OCopy, k, TMP(RAX), r0, R); else - emit(OCopy, k, TMP(XMM0), r, R); - return; - case JJnz:; + emit(OCopy, k, TMP(XMM0), r0, R); } +} + +static void +seljmp(Blk *b, Fn *fn) +{ + Ref r; + int c, k; + Ins *fi; + + if (b->jmp.type == JRet0 || b->jmp.type == JJmp) + return; + assert(b->jmp.type == JJnz); r = b->jmp.arg; b->jmp.arg = R; assert(!req(r, R)); @@ -428,57 +529,6 @@ seljmp(Blk *b, Fn *fn) b->jmp.type = JXJc + ICne; } -struct AClass { - int inmem; - int align; - uint size; - int cls[2]; -}; - -static void -aclass(AClass *a, Typ *t) -{ - int e, s, n, cls; - uint sz, al; - - sz = t->size; - al = 1u << t->align; - - /* the ABI requires sizes to be rounded - * up to the nearest multiple of 8, moreover - * it makes it easy load and store structures - * in registers - */ - if (al < 8) - al = 8; - sz = (sz + al-1) & -al; - - a->size = sz; - a->align = t->align; - - if (t->dark || sz > 16) { - /* large or unaligned structures are - * required to be passed in memory - */ - a->inmem = 1; - return; - } - - for (e=0, s=0; e<2; e++) { - cls = -1; - for (n=0; n<8 && t->seg[s].len; s++) { - if (t->seg[s].flt) { - if (cls == -1) - cls = Kd; - } else - cls = Kl; - n += t->seg[s].len; - } - assert(n <= 8); - a->cls[e] = cls; - } -} - static int classify(Ins *i0, Ins *i1, AClass *ac, int op) { @@ -578,25 +628,6 @@ calluse(Ins i, int p[2]) return b; } -static void -blit(Ref rstk, uint soff, Ref rsrc, uint sz, Fn *fn) -{ - Ref r, r1; - uint boff; - - /* it's an impolite blit, we might go across the end - * of the source object a little bit... */ - for (boff=0; sz>0; sz-=8, soff+=8, boff+=8) { - r = newtmp("abi", fn); - r1 = newtmp("abi", fn); - emit(OStorel, 0, R, r, r1); - emit(OAdd, Kl, r1, rstk, getcon(soff, fn)); - r1 = newtmp("abi", fn); - emit(OLoad, Kl, r, r1, R); - emit(OAdd, Kl, r1, rsrc, getcon(boff, fn)); - } -} - static Ref rarg(int ty, int *ni, int *ns) { @@ -643,7 +674,7 @@ selcall(Fn *fn, Ins *i0, Ins *i1) if (i->op == OArgc) { if (a->size > 8) { r2 = rarg(a->cls[1], &ni, &ns); - r = newtmp("abi", fn); + r = newtmp("abi", Kl, fn); emit(OLoad, a->cls[1], r2, r, R); emit(OAdd, Kl, r, i->arg[1], getcon(8, fn)); } @@ -652,7 +683,7 @@ selcall(Fn *fn, Ins *i0, Ins *i1) emit(OCopy, i->cls, r1, i->arg[0], R); } - r = newtmp("abi", fn); + r = newtmp("abi", Kl, fn); for (i=i0, a=ac, off=0; i<i1; i++, a++) { if (!a->inmem) continue; @@ -661,19 +692,20 @@ selcall(Fn *fn, Ins *i0, Ins *i1) off += off & 15; blit(r, off, i->arg[1], a->size, fn); } else { - r1 = newtmp("abi", fn); + r1 = newtmp("abi", Kl, fn); emit(OStorel, 0, R, i->arg[0], r1); emit(OAdd, Kl, r1, r, getcon(off, fn)); } off += a->size; } - emit(OSAlloc, Kl, r, getcon(stk, fn), R); + if (stk) + emit(OSAlloc, Kl, r, getcon(stk, fn), R); } static void selpar(Fn *fn, Ins *i0, Ins *i1) { - AClass *ac, *a; + AClass *ac, *a, aret; Ins *i; int ni, ns, s, al; Ref r, r1; @@ -684,6 +716,16 @@ selpar(Fn *fn, Ins *i0, Ins *i1) curi = insb; ni = ns = 0; assert(NAlign == 3); + + if (fn->retty >= 0) { + aclass(&aret, &typ[fn->retty]); + if (aret.inmem) { + r = newtmp("abi", Kl, fn); + *curi++ = (Ins){OCopy, r, {rarg(Kl, &ni, &ns)}, Kl}; + fn->retr = r; + } + } + s = 4; for (i=i0, a=ac; i<i1; i++, a++) { switch (a->inmem) { @@ -701,12 +743,12 @@ selpar(Fn *fn, Ins *i0, Ins *i1) } r1 = rarg(a->cls[0], &ni, &ns); if (i->op == OParc) { - r = newtmp("abi", fn); + r = newtmp("abi", Kl, fn); *curi++ = (Ins){OCopy, r, {r1}, Kl}; a->cls[0] = r.val; if (a->size > 8) { r1 = rarg(a->cls[1], &ni, &ns); - r = newtmp("abi", fn); + r = newtmp("abi", Kl, fn); *curi++ = (Ins){OCopy, r, {r1}, Kl}; a->cls[1] = r.val; } @@ -724,7 +766,7 @@ selpar(Fn *fn, Ins *i0, Ins *i1) *curi++ = (Ins){OAlloc+al, r1, {getcon(a->size, fn)}, Kl}; *curi++ = (Ins){OStorel, R, {r, r1}, 0}; if (a->size > 8) { - r = newtmp("abi", fn); + r = newtmp("abi", Kl, fn); *curi++ = (Ins){OAdd, r, {r1, getcon(8, fn)}, Kl}; r1 = TMP(a->cls[1]); *curi++ = (Ins){OStorel, R, {r1, r}, 0}; @@ -916,9 +958,10 @@ isel(Fn *fn) b->nins = n; b->ins = i0; - /* lower function calls */ + /* lower function calls and returns */ for (b=fn->start; b; b=b->link) { curi = &insb[NIns]; + selret(b, fn); for (i=&b->ins[b->nins]; i!=b->ins;) { if ((--i)->op == OCall) { for (i0=i; i0>b->ins; i0--) |