diff options
Diffstat (limited to 'ins.c')
| -rw-r--r-- | ins.c | 195 |
1 files changed, 195 insertions, 0 deletions
@@ -0,0 +1,195 @@ +#include "all.h" + +void +addins(Ins **pvins, uint *pnins, Ins *i) +{ + if (i->op == Onop) + return; + vgrow(pvins, ++(*pnins)); + (*pvins)[(*pnins)-1] = *i; +} + +void +addbins(Blk *b, Ins **pvins, uint *pnins) +{ + Ins *i; + + for (i = b->ins; i < &b->ins[b->nins]; i++) + addins(pvins, pnins, i); +} + +static int +unusedins(Fn *fn, Ins *i); + +static int +unusedtmp(Fn *fn, Tmp *t) +{ + if (t->nuse == 0) + return 1; + if (t->nuse == 1) + if (t->use[0].type == UIns) + return unusedins(fn, t->use[0].u.ins); + return 0; +} + +static int +unusedtmpref(Fn *fn, Ref r) +{ + if (rtype(r) != RTmp) + return 0; + return unusedtmp(fn, &fn->tmp[r.val]); +} + +static int +unusedins(Fn *fn, Ins *i) +{ + if (!INRANGE(i->op, Opar, Ocall)) + if (unusedtmpref(fn, i->to)) + return 1; + return 0; +} + +/* replace unused ins with nop */ +/* needs use; breaks use */ +void +nopunused(Fn *fn) +{ + Blk *b; + Ins *i; + + for (b = fn->start; b; b = b->link) + for (i = b->ins; i < &b->ins[b->nins]; i++) + if (unusedins(fn, i)) + *i = (Ins){.op = Onop}; +} + +typedef struct FromLoc FromLoc; +struct FromLoc { + InsLoc from; + uint ton; +}; + +static int +loccmp(InsLoc *la, InsLoc *lb) +{ + if (la->bid != lb->bid) + return (int)la->bid - (int)lb->bid; + return la->insn - lb->insn; +} + +static int +tocmp(const void *a, const void *b) +{ + InsMov *ma, *mb; + + ma = (InsMov*)a; + mb = (InsMov*)b; + return loccmp(&ma->to, &mb->to); +} + +static int +fromcmp(const void *a, const void *b) +{ + FromLoc *fa, *fb; + + fa = (FromLoc*)a; + fb = (FromLoc*)b; + return loccmp(&fa->from, &fb->from); +} + +static int +loceq(InsLoc *a, InsLoc *b) +{ + return a->bid == b->bid && a->insn == b->insn; +} + +/* after, mov is sorted by to, and to.insn, from.insn are updated */ +void +movins(Fn *fn, InsMov *mov, uint nmov, int del) +{ + Blk *b, *b2; + uint bid, n, fromn, ton, ifromn, nins; + FromLoc *from; + uint *newbnins; + Ins **newbins, *vins; + + qsort(mov, nmov, sizeof mov[0], tocmp); + + from = emalloc(nmov * sizeof from[0]); + for (n = 0; n < nmov; n++) { + from[n].from = mov[n].from; + from[n].ton = n; + } + qsort(from, nmov, sizeof from[0], fromcmp); + + nins = 0; + vins = vnew(nins, sizeof vins[0], PFn); + + newbnins = emalloc(fn->nblk * sizeof newbnins[0]); + newbins = emalloc(fn->nblk * sizeof newbins[0]); + + /* populate new ins buffers */ + /* update mov to.insn, from insn */ + fromn = ton = 0; + for (bid = 0; bid < fn->nblk; bid++) { + /* no moves to this block */ + if (nmov <= ton || mov[ton].to.bid != bid) { + while (fromn < nmov && from[fromn].from.bid == bid) + fromn++; + continue; + } + b = fn->rpo[bid]; + nins = 0; + for (ifromn = 0; ifromn < b->nins; ifromn++) { + /* insert new ins, update to */ + while (ton < nmov && loceq(&mov[ton].to, &(InsLoc){.bid = bid, .insn = ifromn})) { + b2 = fn->rpo[mov[ton].from.bid]; + assert(mov[ton].from.insn < b2->nins); + addins(&vins, &nins, &b2->ins[mov[ton].from.insn]); + mov[ton++].to.insn = nins-1; + } + /* update from */ + while (fromn < nmov && loceq(&from[fromn].from, &(InsLoc){.bid = bid, .insn = ifromn})) + from[fromn++].from.insn = nins; + /* copy original ins */ + addins(&vins, &nins, &b->ins[ifromn]); + } + /* append new ins, update to */ + while (ton < nmov && mov[ton].to.bid == bid) { + assert(mov[ton].to.insn == b->nins); + b2 = fn->rpo[mov[ton].from.bid]; + assert(mov[ton].from.insn < b2->nins); + addins(&vins, &nins, &b2->ins[mov[ton].from.insn]); + mov[ton++].to.insn = nins-1; + } + assert(ifromn == b->nins); + /* idup(&newbins[bid], vins, nins); */ + newbins[bid] = vins; + vins = vnew(0, sizeof vins[0], PFn); + newbnins[bid] = nins; + } + assert(fromn == nmov); + assert(ton == nmov); + + /* install new b->ins */ + for (bid = 0; bid < fn->nblk; bid++) { + if (newbnins[bid] == 0) + continue; + b = fn->rpo[bid]; + b->ins = newbins[bid]; + b->nins = newbnins[bid]; + } + + /* remove from ins, update mov from insn */ + for (fromn = 0; fromn < nmov; fromn++) { + b = fn->rpo[from[fromn].from.bid]; + assert(from[fromn].from.insn < b->nins); + if (del) + b->ins[from[fromn].from.insn] = (Ins){.op = Onop}; + mov[from[fromn].ton].from.insn = from[fromn].from.insn; + } + + free(from); + free(newbins); + free(newbnins); +} |
