diff options
Diffstat (limited to 'src/ir_inliner.c')
| -rw-r--r-- | src/ir_inliner.c | 106 |
1 files changed, 87 insertions, 19 deletions
diff --git a/src/ir_inliner.c b/src/ir_inliner.c index c1c36e2..685815f 100644 --- a/src/ir_inliner.c +++ b/src/ir_inliner.c @@ -1,7 +1,9 @@ #include "ir.h" +#include "obj.h" typedef struct SavedFunc { - uint ninstrtab; + bool emitted; + uint ninstrtab, ncontab, ncalltab, nphitab; Instr *instrtab; IRCon *contab; IRCall *calltab; @@ -17,16 +19,16 @@ enum { MAX_INLINED_FN_NINS = 50, MAX_INLINED_FN_NBLK = 16, }; static pmap_of(SavedFunc *) savedfns; +static Arena *savearena; bool maybeinlinee(Function *fn) { - static Arena *savearena; extern int ninstrtab, nfreeinstr; // TODO better heuristics if (ccopt.o < OPT1) return 0; - if (!fn->inlin && ccopt.o < OPT2) return 0; + if (!(fn->inlin || (!fn->globl && ccopt.o >= OPT2))) return 0; if (ninstrtab - nfreeinstr > MAX_INLINED_FN_NINS) return 0; if (fn->nblk > MAX_INLINED_FN_NBLK) return 0; for (int i = 0; i < fn->nabiarg; ++i) { @@ -50,20 +52,14 @@ maybeinlinee(Function *fn) if (fn->abiarg) sv->abiarg = alloccopy(&savearena, fn->abiarg, sizeof *sv->abiarg * fn->nabiarg, 0); sv->nabiarg = fn->nabiarg; - if ((sv->nabiret = fn->nabiret) > 0) - memcpy(sv->abiret, fn->abiret, sizeof sv->abiret); + sv->nabiret = fn->nabiret; + memcpy(sv->abiret, fn->abiret, sizeof sv->abiret); Block *bmap[MAX_INLINED_FN_NBLK]; Block *b = fn->entry; int id = 0; do { b->id = id++; Block *q = alloccopy(&savearena, b, sizeof *b, 0); - if (q->phi.n) - q->phi.p = alloccopy(&savearena, q->phi.p, sizeof *q->phi.p * q->phi.n, 0); - if (q->ins.n) - q->ins.p = alloccopy(&savearena, q->ins.p, sizeof *q->ins.p * q->ins.n, 0); - if (q->npred > 1) - q->_pred = alloccopy(&savearena, q->_pred, sizeof *q->_pred * q->npred, 0); q->lprev = NULL; q->idom = NULL; bmap[b->id] = q; @@ -81,8 +77,8 @@ maybeinlinee(Function *fn) } while ((b = b->lnext)); sv->instrtab = alloccopy(&savearena, instrtab, sizeof *instrtab * (sv->ninstrtab = ninstrtab), 0); - sv->contab = alloccopy(&savearena, contab.p, sizeof *contab.p * contab.n, 0); - if (calltab.n) { + sv->contab = alloccopy(&savearena, contab.p, sizeof *contab.p * (sv->ncontab = contab.n), 0); + if ((sv->ncalltab = calltab.n)) { sv->calltab = alloccopy(&savearena, calltab.p, sizeof *calltab.p * calltab.n, 0); for (int i = 0; i < calltab.n; ++i) { if (sv->calltab[i].abiarg) @@ -90,11 +86,9 @@ maybeinlinee(Function *fn) sv->calltab[i].narg * sizeof *sv->calltab[i].abiarg, 0); } } - if (phitab.n) { - sv->phitab = alloc(&savearena, sizeof *phitab.p * phitab.n, 0); - for (int i = 0; i < phitab.n; ++i) { - sv->phitab[i] = alloccopy(&savearena, phitab.p[i], sizeof *phitab.p[i] * xbcap(phitab.p[i]), 0); - } + if ((sv->nphitab = phitab.n)) { + sv->phitab = alloccopy(&savearena, phitab.p, sizeof *phitab.p * phitab.n, 0); + phitab.n = 0; } pmap_set(&savedfns, fn->name, sv); return 1; @@ -180,7 +174,7 @@ inlcall(Function *fn, Block *blk, int curi, SavedFunc *sv) for (int i = 0; i < b->phi.n; ++i) { int t = b->phi.p[i]; Ref *refs = NULL, - *src = sv->phitab[sv->instrtab[t].l.i]; + *src = sv->phitab[sv->instrtab[t].l.i]; xbgrow(&refs, b->npred); for (int i = 0; i < b->npred; ++i) refs[i] = mapref(instrmap, sv, src[i]); @@ -304,4 +298,78 @@ doinline(Function *fn) } while ((b = b->lnext) != fn->entry); } +static Function +rematerialize(Arena **arena, internstr name, SavedFunc *sv) +{ + Function fn = { arena, .name = name, .globl = 0/*always localG*/, .fnty = sv->fnty, + .retty = sv->retty, .abiarg = sv->abiarg, .nabiarg = sv->nabiarg, + .abiret = {sv->abiret[0], sv->abiret[1]}, .nabiret = sv->nabiret, + }; + irinit(&fn); + extern int ninstrtab; + ninstrtab = sv->ninstrtab; + memcpy(instrtab, sv->instrtab, ninstrtab * sizeof *instrtab); + vpushn(&calltab, sv->calltab, sv->ncalltab); + vpushn(&phitab, sv->phitab, sv->nphitab); + vpushn(&contab, sv->contab, sv->ncontab); + + fn.nblk = 0; + struct Block *last = fn.entry = NULL; + for (struct Block *b = sv->entry, *next; b; b = next) { + next = b->lnext; + if (last) { + b->lprev = last; + last->lnext = b; + } else { + fn.entry = b; + b->lprev = b; + } + last = b; + if (!next) { + fn.entry->lprev = b; + b->lnext = fn.entry; + } + ++fn.nblk; + } + fn.entry->lprev->lnext = fn.entry; + memset(instruse, 0, sizeof *instruse * ninstrtab); + filluses(&fn); + + return fn; +} + +void +emitxinlfns(bool all) +{ + enum { N = 1 << 12 }; + static union { char m[sizeof(Arena) + N]; Arena *_align; } amem[2]; + Arena *arena = (void *)amem[0].m, *passarena = (void *)amem[1].m; + arena->cap = N; + passarena->cap = N; + + /* looping until fixpoint because emitting functions might generate + * references to other stashed functions, which might have already been + * visited, but they need to be visited them again */ + for (bool change = 1; change;) { + change = 0; + SavedFunc **psv, *sv; + internstr name; + pmap_each(&savedfns, name, psv) { + sv = *psv; + if (!sv->emitted && (all || fnisneeded(name))) { + sv->emitted = 1; + Function fn = rematerialize(&arena, name, sv); + fn.passarena = &passarena; + if (ccopt.dbg.y) { + bfmt(ccopt.dbgout, "<< Rematerialize inlinee >>\n"); + irdump(&fn); + } + irfini_end(&fn); + change = 1; + freearena(&arena); + } + } + } +} + /* vim:set ts=3 sw=3 expandtab: */ |