summary refs log tree commit diff
path: root/simpl.c
diff options
context:
space:
mode:
Diffstat (limited to 'simpl.c')
-rw-r--r--simpl.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/simpl.c b/simpl.c
new file mode 100644
index 0000000..7001301
--- /dev/null
+++ b/simpl.c
@@ -0,0 +1,82 @@
+#include "all.h"
+
+static void
+blit(Ref sd[2], int sz, Fn *fn)
+{
+	struct { int st, ld, cls, size; } *p, tbl[] = {
+		{ Ostorel, Oload,   Kl, 8 },
+		{ Ostorew, Oload,   Kw, 4 },
+		{ Ostoreh, Oloaduh, Kw, 2 },
+		{ Ostoreb, Oloadub, Kw, 1 }
+	};
+	Ref r, r1, ro;
+	int off, fwd, n;
+
+	fwd = sz >= 0;
+	sz = abs(sz);
+	off = fwd ? sz : 0;
+	for (p=tbl; sz; p++)
+		for (n=p->size; sz>=n; sz-=n) {
+			off -= fwd ? n : 0;
+			r = newtmp("blt", Kl, fn);
+			r1 = newtmp("blt", Kl, fn);
+			ro = getcon(off, fn);
+			emit(p->st, 0, R, r, r1);
+			emit(Oadd, Kl, r1, sd[1], ro);
+			r1 = newtmp("blt", Kl, fn);
+			emit(p->ld, p->cls, r, r1, R);
+			emit(Oadd, Kl, r1, sd[0], ro);
+			off += fwd ? 0 : n;
+		}
+}
+
+static void
+ins(Ins **pi, int *new, Blk *b, Fn *fn)
+{
+	ulong ni;
+	Ins *i;
+
+	i = *pi;
+	/* simplify more instructions here;
+	 * copy 0 into xor, mul 2^n into shift,
+	 * bit rotations, ... */
+	switch (i->op) {
+	case Oblit1:
+		assert(i > b->ins);
+		assert((i-1)->op == Oblit0);
+		if (!*new) {
+			curi = &insb[NIns];
+			ni = &b->ins[b->nins] - (i+1);
+			curi -= ni;
+			icpy(curi, i+1, ni);
+			*new = 1;
+		}
+		blit((i-1)->arg, rsval(i->arg[0]), fn);
+		*pi = i-1;
+		break;
+	default:
+		if (*new)
+			emiti(*i);
+		break;
+	}
+}
+
+void
+simpl(Fn *fn)
+{
+	Blk *b;
+	Ins *i;
+	int new;
+
+	for (b=fn->start; b; b=b->link) {
+		new = 0;
+		for (i=&b->ins[b->nins]; i!=b->ins;) {
+			--i;
+			ins(&i, &new, b, fn);
+		}
+		if (new) {
+			b->nins = &insb[NIns] - curi;
+			idup(&b->ins, curi, b->nins);
+		}
+	}
+}