summary refs log tree commit diff
path: root/lisc/isel.c
diff options
context:
space:
mode:
authorQuentin Carbonneaux <quentin.carbonneaux@yale.edu>2015-07-19 07:03:52 -0400
committerQuentin Carbonneaux <quentin.carbonneaux@yale.edu>2015-09-15 23:01:28 -0400
commita244ca17f1c4e81a92d26119d4f0b5137e93476b (patch)
tree7c0ac446eb22cde4a586e563c76f0d9bd7eb3899 /lisc/isel.c
parenta280eb6597da33ea23f8349f74a20416e5519e7e (diff)
downloadroux-a244ca17f1c4e81a92d26119d4f0b5137e93476b.tar.gz
start simple work on isel
Diffstat (limited to 'lisc/isel.c')
-rw-r--r--lisc/isel.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/lisc/isel.c b/lisc/isel.c
new file mode 100644
index 0000000..d47ed0f
--- /dev/null
+++ b/lisc/isel.c
@@ -0,0 +1,107 @@
+#include "lisc.h"
+
+/* For x86_64, we have to:
+ *
+ * - add dummy uses for the second argument
+ *   after non-commutative arithmetic
+ *   operations (this prevents the reg.
+ *   allocator to get 'eax = sub ebx eax')
+ *
+ * - check that constants are used only in
+ *   places allowed by the machine
+ *
+ * - explicit machine register contraints
+ *   on instructions like division.
+ *
+ * - lower calls (future, I have to think
+ *   about their representation and the
+ *   way I deal with structs/unions in the
+ *   ABI)
+ */
+
+extern Ins insb[NIns]; /* shared work buffer */
+static Ins *curi;
+
+static void
+emit(short op, Ref to, Ref arg0, Ref arg1)
+{
+	if (curi == insb)
+		diag("isel: too many instructions");
+	*curi-- = (Ins){op, to, {arg0, arg1}};
+}
+
+static void
+sel(Ins *i, Fn *fn)
+{
+	int t;
+	Ref r0, r1;
+
+	switch (i->op) {
+	case ODiv:
+		r0 = SYM(RAX);
+		r1 = SYM(RDX);
+	if (0) {
+	case ORem:
+		r0 = SYM(RDX);
+		r1 = SYM(RAX);
+	}
+		emit(OCopy, i->to, r0, R);
+		emit(OCopy, R, r1, R);
+		if (rtype(i->arg[1]) == RConst) {
+			/* immediates not allowed for
+			 * divisions in x86
+			 */
+			t = fn->ntmp++;
+			r0 = SYM(t);
+		} else
+			r0 = i->arg[1];
+		emit(OXDiv, R, r0, R);
+		emit(OXCltd, SYM(RDX), R, R);
+		emit(OCopy, SYM(RAX), i->arg[0], R);
+		if (rtype(i->arg[1]) == RConst)
+			emit(OCopy, r0, i->arg[1], R);
+		break;
+	case OAdd:
+	case OSub:
+		if (!opdesc[i->op].commut
+		&& rtype(i->arg[1]) != RConst)
+			emit(OCopy, R, i->arg[1], R);
+		emit(i->op, i->to, i->arg[0], i->arg[1]);
+		break;
+	default:
+		diag("isel: non-exhaustive implementation");
+	}
+}
+
+/* instruction selection
+ */
+void
+isel(Fn *fn)
+{
+	Blk *b;
+	Ins *i;
+	int t0, t, nins;
+
+	t0 = fn->ntmp;
+	for (b=fn->start; b; b=b->link) {
+		curi = &insb[NIns-1];
+		for (i=&b->ins[b->nins]; i!=b->ins;) {
+			sel(--i, fn);
+		}
+		nins = &insb[NIns-1] - curi;
+		curi++;
+		free(b->ins);
+		b->ins = alloc(nins * sizeof b->ins[0]);
+		memcpy(b->ins, curi, nins * sizeof b->ins[0]);
+		b->nins = nins;
+	}
+	if (fn->ntmp == t0)
+		return;
+	fn->sym = realloc(fn->sym, fn->ntmp * sizeof(Sym));
+	if (!fn->sym)
+		diag("isel: out of memory");
+	for (t=t0; t<fn->ntmp; t++) {
+		fn->sym[t].type = STmp;
+		sprintf(fn->sym[t].name, "isel%d", t-t0);
+	}
+}