summary refs log tree commit diff
path: root/lisc/emit.c
diff options
context:
space:
mode:
Diffstat (limited to 'lisc/emit.c')
-rw-r--r--lisc/emit.c117
1 files changed, 117 insertions, 0 deletions
diff --git a/lisc/emit.c b/lisc/emit.c
new file mode 100644
index 0000000..9841c14
--- /dev/null
+++ b/lisc/emit.c
@@ -0,0 +1,117 @@
+#include "lisc.h"
+
+
+static void
+eref(Ref r, Fn *fn, FILE *f)
+{
+	switch (rtype(r)) {
+	case RSym:
+		assert(fn->sym[r.val].type == SReg);
+		fprintf(f, "%%%s", fn->sym[r.val].name);
+		break;
+	case RSlot:
+		fprintf(f, "-%d(%%rbp)", 8 * r.val);
+		break;
+	case RConst:
+		fprintf(f, "$%d", (int)r.val);
+		break;
+	default:
+		diag("emitref: invalid reference");
+	}
+}
+
+static void
+eop(char *op, Ref a, Ref b, Fn *fn, FILE *f)
+{
+	fprintf(f, "\t%s ", op);
+	eref(a, fn, f);
+	if (!req(b, R)) {
+		fprintf(f, ", ");
+		eref(b, fn, f);
+	}
+	fprintf(f, "\n");
+}
+
+static void
+eins(Ins i, Fn *fn, FILE *f)
+{
+	static char *opi[] = {
+		[OAdd] = "add",
+		[OSub] = "sub",
+	};
+
+	switch (i.op) {
+	case OAdd:
+	case OSub:
+		if (!req(i.to, i.arg[0]))
+			eop("mov", i.arg[0], i.to, fn, f);
+		eop(opi[i.op], i.arg[1], i.to, fn, f);
+		break;
+	case OStore:
+		i.to = i.arg[1];
+		/* fall through */
+	case OCopy:
+	case OLoad:
+		if (!req(i.arg[0], i.to))
+			eop("mov", i.arg[0], i.to, fn, f);
+		break;
+	case OSwap:
+		eop("xchg", i.arg[0], i.arg[1], fn, f);
+		break;
+	case ONop:
+		break;
+	default:
+		diag("emit: unhandled instruction");
+	}
+}
+
+void
+emitfn(Fn *fn, FILE *f)
+{
+	char *js;
+	Blk *b, *s;
+	Ins *i;
+
+	fprintf(f,
+		".text\n"
+		".globl liscf\n"
+		".type liscf, @function\n"
+		"liscf:\n"
+		"\tpush %%rbp\n"
+		"\tmov %%rsp, %%rbp\n"
+		"\tsub $%u, %%rsp\n",
+		fn->nspill * 8
+	);
+	for (b=fn->start; b; b=b->link) {
+		fprintf(f, ".L%s:\n", b->name);
+		for (i=b->ins; i-b->ins < b->nins; i++)
+			eins(*i, fn, f);
+		switch (b->jmp.type) {
+		case JRet:
+			fprintf(f,
+				"\tleave\n"
+				"\tret\n"
+			);
+			break;
+		case JJmp:
+			if (b->s1 != b->link)
+				fprintf(f, "\tjmp .L%s\n", b->s1->name);
+			break;
+		case JJez:
+			if (b->s1 == b->link) {
+				js = "jnz";
+				s = b->s2;
+			} else if (b->s2 == b->link) {
+				js = "jz";
+				s = b->s1;
+			} else
+				diag("emit: unhandled jump (1)");
+			eop("test", b->jmp.arg, b->jmp.arg, fn, f);
+			fprintf(f, "\t%s .L%s\n", js, s->name);
+			break;
+		default:
+			diag("emit: unhandled jump (2)");
+		}
+	}
+
+}