diff options
author | Quentin Carbonneaux <quentin.carbonneaux@yale.edu> | 2015-09-14 23:36:26 -0400 |
---|---|---|
committer | Quentin Carbonneaux <quentin.carbonneaux@yale.edu> | 2015-09-15 23:01:33 -0400 |
commit | f7bfa2e435c78917bd6df0c80e7e488751dac58c (patch) | |
tree | ff55a42ecc560ccde7af547b59c71b94afe6844b /lisc/isel.c | |
parent | bad74e6dce897df9f21cea5bf0a32df298856351 (diff) | |
download | roux-f7bfa2e435c78917bd6df0c80e7e488751dac58c.tar.gz |
heavy modification of call handling
The IR generated by calls was very bulky because two instructions were used for marking the live range of a clobber. This patch attempts to store the information of what registers are use/def/clobber in the call instruction itself, this leads to more compact code (even more when we'll have SSE registers). However, I find that the amount of extra code needed is not really easonable. Fortunately it is not too invasive, thus if the complexity creeps in, it should be easy to revert.
Diffstat (limited to 'lisc/isel.c')
-rw-r--r-- | lisc/isel.c | 60 |
1 files changed, 48 insertions, 12 deletions
diff --git a/lisc/isel.c b/lisc/isel.c index 6928a1a..1712333 100644 --- a/lisc/isel.c +++ b/lisc/isel.c @@ -442,10 +442,51 @@ classify(AInfo *a, Typ *t) } } +int rsave[NRSave] = {RDI, RSI, RDX, RCX, R8, R9, R10, R11, RAX}; + +uint64_t calldef(Ins i, int *p) +{ + uint64_t b; + int n; + + n = i.arg[1].val & 15; + b = 1ll << RAX; + if (n == 2) + b |= 1ll << RDX; + if (p) + *p = n; + return b; +} + +uint64_t calluse(Ins i, int *p) +{ + uint64_t b; + int j, n; + + n = (i.arg[1].val >> 4) & 15; + for (j = 0, b = 0; j < n; j++) + b |= 1ll << rsave[j]; + if (p) + *p = n; + return b; +} + +uint64_t callclb(Ins i, int *p) +{ + uint64_t b; + int j, n; + + n = (i.arg[1].val >> 4) & 15; + for (j = n, b = 0; j < NRSave; j++) + b |= 1ll << rsave[j]; + if (p) + *p = n; + return b; +} + static void selcall(Fn *fn, Ins *i0, Ins *i1) { - static int ireg[8] = {RDI, RSI, RDX, RCX, R8, R9, R10, R11}; Ins *i; AInfo *ai, *a; int nint, nsse, ni, ns, n; @@ -497,20 +538,15 @@ selcall(Fn *fn, Ins *i0, Ins *i1) } stk += stk & 15; - if (rtype(i1->arg[1]) == RTyp) + if (!req(i1->arg[1], R)) diag("struct-returning function not implemented"); if (stk) { r = newcon(-(int64_t)stk, fn); emit(OSAlloc, 0, R, r, R); } - for (n=0; n<8; n++) - emit(OCopy, 0, R, TMP(ireg[n]), R); emit(OCopy, i1->wide, i1->to, TMP(RAX), R); - emit(OCall, 0, R, i->arg[0], R); - emit(OCopy, 1, TMP(RAX), R, R); - for (n=6-nint; n<8; n++) - emit(OCopy, 1, TMP(ireg[n]), R, R); + emit(OCall, 0, R, i->arg[0], CALL(1 + ((6-nint) << 4))); for (i=i0, a=ai, ni=0; i<i1; i++, a++) { if (a->inmem) @@ -519,18 +555,18 @@ selcall(Fn *fn, Ins *i0, Ins *i1) if (a->rty[0] == RSse || a->rty[1] == RSse) diag("isel: unsupported float struct"); if (a->size > 8) { - r = TMP(ireg[ni+1]); + r = TMP(rsave[ni+1]); r1 = newtmp(fn); emit(OLoad, 1, r, r1, R); r = newcon(8, fn); emit(OAdd, 1, r1, i->arg[1], r); - r = TMP(ireg[ni]); + r = TMP(rsave[ni]); ni += 2; } else - r = TMP(ireg[ni++]); + r = TMP(rsave[ni++]); emit(OLoad, 1, r, i->arg[1], R); } else { - r = TMP(ireg[ni++]); + r = TMP(rsave[ni++]); emit(OCopy, i->wide, r, i->arg[0], R); } } |