aboutsummaryrefslogtreecommitdiff
path: root/ins.c
diff options
context:
space:
mode:
Diffstat (limited to 'ins.c')
-rw-r--r--ins.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/ins.c b/ins.c
new file mode 100644
index 0000000..1935a95
--- /dev/null
+++ b/ins.c
@@ -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);
+}