commit a244ca17f1c4e81a92d26119d4f0b5137e93476b
parent a280eb6597da33ea23f8349f74a20416e5519e7e
Author: Quentin Carbonneaux <quentin.carbonneaux@yale.edu>
Date: Sun, 19 Jul 2015 07:03:52 -0400
start simple work on isel
Diffstat:
| M | lisc/Makefile | | | 4 | ++-- |
| A | lisc/isel.c | | | 107 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 109 insertions(+), 2 deletions(-)
diff --git a/lisc/Makefile b/lisc/Makefile
@@ -1,7 +1,7 @@
BIN = lisc
-OBJ = main.o parse.o ssa.o live.o
+OBJ = main.o parse.o ssa.o live.o isel.o
-CFLAGS = -Wall -Wextra -std=c99 -g
+CFLAGS = -Wall -Wextra -std=c11 -g
$(BIN): $(OBJ)
$(CC) $(LDFLAGS) $(OBJ) -o $@
diff --git a/lisc/isel.c 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);
+ }
+}