summary refs log tree commit diff
path: root/lisc
diff options
context:
space:
mode:
Diffstat (limited to 'lisc')
-rw-r--r--lisc/emit.c13
-rw-r--r--lisc/isel.c40
-rw-r--r--lisc/lisc.h2
-rw-r--r--lisc/parse.c2
4 files changed, 54 insertions, 3 deletions
diff --git a/lisc/emit.c b/lisc/emit.c
index 15be31e..a08ad52 100644
--- a/lisc/emit.c
+++ b/lisc/emit.c
@@ -128,6 +128,7 @@ eins(Ins i, Fn *fn, FILE *f)
 	static char *otoa[NOp] = {
 		[OAdd]    = "add",
 		[OSub]    = "sub",
+		[OAnd]    = "and",
 		[OLoad]   = "mov",
 		[OLoadss] = "movsw",
 		[OLoadus] = "movzw",
@@ -140,12 +141,13 @@ eins(Ins i, Fn *fn, FILE *f)
 		[OStores - OStorel] = "w",
 		[OStoreb - OStorel] = "b",
 	};
-	int r;
+	int reg;
 	int64_t val;
 
 	switch (i.op) {
 	case OAdd:
 	case OSub:
+	case OAnd:
 		if (req(i.to, i.arg[1])) {
 			if (i.op == OSub) {
 				eop("neg", i.to, R, fn, f);
@@ -177,8 +179,8 @@ eins(Ins i, Fn *fn, FILE *f)
 	case OStoreb:
 		fprintf(f, "\tmov%s ", stoa[i.op - OStorel]);
 		if (rtype(i.arg[0]) == RReg) {
-			r = RBASE(i.arg[0].val);
-			fprintf(f, "%%%s", rsub[r][i.op - OStorel]);
+			reg = RBASE(i.arg[0].val);
+			fprintf(f, "%%%s", rsub[reg][i.op - OStorel]);
 		} else
 			eref(i.arg[0], fn, f);
 		fprintf(f, ", ");
@@ -200,6 +202,11 @@ eins(Ins i, Fn *fn, FILE *f)
 		eref(i.to, fn, f);
 		fprintf(f, "\n");
 		break;
+	case OAlloc:
+		eop("sub", i.arg[0], REG(RSP), fn, f);
+		if (!req(i.to, R))
+			eop("mov", REG(RSP), i.to, fn ,f);
+		break;
 	case OSwap:
 		eop("xchg", i.arg[0], i.arg[1], fn, f);
 		break;
diff --git a/lisc/isel.c b/lisc/isel.c
index 7c634d8..5b83081 100644
--- a/lisc/isel.c
+++ b/lisc/isel.c
@@ -42,6 +42,22 @@ newtmp(int type, Fn *fn)
 	return TMP(t);
 }
 
+static Ref
+newcon(int64_t val, Fn *fn)
+{
+	int c;
+
+	for (c=0; c<fn->ncon; c++)
+		if (fn->con[c].type == CNum && fn->con[c].val == val)
+			return CON(c);
+	fn->ncon++;
+	fn->con = realloc(fn->con, fn->ncon * sizeof fn->con[0]);
+	if (!fn->con)
+		diag("isel: out of memory");
+	fn->con[c] = (Con){.type = CNum, .val = val};
+	return CON(c);
+}
+
 static int
 noimm(Ref r, Fn *fn)
 {
@@ -96,6 +112,7 @@ sel(Ins i, Fn *fn)
 {
 	Ref r0, r1, ra, rd;
 	int n, ty, c;
+	int64_t val;
 
 	switch (i.op) {
 	case ODiv:
@@ -166,6 +183,29 @@ Emit:
 			}
 		}
 		break;
+	case OAlloc:
+		/* we need to make sure
+		 * the stack remains aligned
+		 * (rsp + 8 = 0) mod 16
+		 * as a consequence, the alloc
+		 * alignment is 8, we can change
+		 * that in the future
+		 */
+		if (rtype(i.arg[0]) == RCon) {
+			val = fn->con[i.arg[0].val].val;
+			val = (val + 15)  & ~INT64_C(15);
+			if (val < 0 || val > INT32_MAX)
+				diag("isel: alloc too large");
+			emit(OAlloc, i.to, newcon(val, fn), R);
+		} else {
+			/* r0 = (i.arg[0] + 15) & -16 */
+			r0 = newtmp(TLong, fn);
+			r1 = newtmp(TLong, fn);
+			emit(OAlloc, i.to, r0, R);
+			emit(OAnd, r0, r1, newcon(-16, fn));
+			emit(OAdd, r1, i.arg[0], newcon(15, fn));
+		}
+		break;
 	default:
 		if (OCmp <= i.op && i.op <= OCmp1) {
 			c = i.op - OCmp;
diff --git a/lisc/lisc.h b/lisc/lisc.h
index cd64e29..abf9c1f 100644
--- a/lisc/lisc.h
+++ b/lisc/lisc.h
@@ -126,6 +126,7 @@ enum {
 	OSub,
 	ODiv,
 	ORem,
+	OAnd,
 	OCmp,
 	OCmp1 = OCmp + NCmp-1,
 	OStorel,
@@ -138,6 +139,7 @@ enum {
 	OLoadsb,
 	OLoadub,
 	OCopy,
+	OAlloc,
 	NPubOp,
 
 	/* reserved instructions */
diff --git a/lisc/parse.c b/lisc/parse.c
index 104c2a2..fc35800 100644
--- a/lisc/parse.c
+++ b/lisc/parse.c
@@ -16,6 +16,7 @@ OpDesc opdesc[NOp] = {
 	[OSub]    = { "sub",    2, 2 },
 	[ODiv]    = { "div",    2, 2 },
 	[ORem]    = { "rem",    2, 2 },
+	[OAnd]    = { "and",    2, 2 },
 	[OStorel] = { "storel", 2, 0 },
 	[OStorew] = { "storew", 2, 0 },
 	[OStores] = { "stores", 2, 0 },
@@ -25,6 +26,7 @@ OpDesc opdesc[NOp] = {
 	[OLoadus] = { "loadus", 1, 0 },
 	[OLoadsb] = { "loadsb", 1, 0 },
 	[OLoadub] = { "loadub", 1, 0 },
+	[OAlloc]  = { "alloc",  1, 1 },
 	[OCopy]   = { "copy",   1, 1 },
 	[ONop]    = { "nop",    0, 0 },
 	[OSwap]   = { "swap",   2, 2 },