summary refs log tree commit diff
path: root/lisc/isel.c
diff options
context:
space:
mode:
authorQuentin Carbonneaux <quentin.carbonneaux@yale.edu>2015-09-11 14:10:05 -0400
committerQuentin Carbonneaux <quentin.carbonneaux@yale.edu>2015-09-15 23:01:33 -0400
commitece185f06705864ae55cbe15fea88c6bc4315f62 (patch)
tree150bc0c4966b16d2d88c8a656c00cf65781f8dba /lisc/isel.c
parent8201c6161e215e4716f3305e3dcb1e6b3de15ea9 (diff)
downloadroux-ece185f06705864ae55cbe15fea88c6bc4315f62.tar.gz
implement aggregate passing in regs
Diffstat (limited to 'lisc/isel.c')
-rw-r--r--lisc/isel.c77
1 files changed, 41 insertions, 36 deletions
diff --git a/lisc/isel.c b/lisc/isel.c
index 6efbd70..a018cd5 100644
--- a/lisc/isel.c
+++ b/lisc/isel.c
@@ -155,7 +155,6 @@ sel(Ins i, Fn *fn)
 		n = 1;
 		goto Emit;
 	case OCall:
-	case OXMovs:
 	case OSAlloc:
 	case OCopy:
 	case OSext:
@@ -446,23 +445,22 @@ classify(AInfo *a, Typ *t)
 static void
 selcall(Fn *fn, Ins *i0, Ins *i1)
 {
-	static int ireg[8] = { RDI, RSI, RDX, RCX, R8, R9, R10, R11 };
+	static int ireg[6] = {RDI, RSI, RDX, RCX, R8, R9};
 	Ins *i;
 	AInfo *ai, *a;
 	int nint, nsse, ni, ns, n;
 	uint stk, sz;
-	Ref r;
+	Ref r, r1;
 
 	ai = alloc((i1-i0) * sizeof ai[0]);
 
 	nint = 6;
 	nsse = 8;
-	stk = 0;
 	for (i=i0, a=ai; i<i1; i++, a++) {
 		if (i->op == OArgc) {
 			classify(a, &typ[i->arg[0].val]);
 			if (a->inmem)
-				goto Mem;
+				continue;
 			ni = ns = 0;
 			for (n=0; n<2; n++)
 				switch (a->rty[n]) {
@@ -476,73 +474,80 @@ selcall(Fn *fn, Ins *i0, Ins *i1)
 			if (nint > ni && nsse > ns) {
 				nint -= ni;
 				nsse -= ns;
-			} else {
+			} else
 				a->inmem = 1;
-			Mem:
-				stk += a->size;
-				if (a->align == 4 && stk % 16)
-					stk += 8;
-			}
 		} else {
 			if (nint > 0) {
 				nint--;
 				a->inmem = 0;
-			} else {
-				stk += 8;
+			} else
 				a->inmem = 1;
-			}
 			a->align = 3;
 			a->size = 8;
 			a->rty[0] = RInt;
 		}
 	}
 
-	if (!req(i1->arg[1], R))
+	for (stk=0, a=&ai[i1-i0]; a>ai;)
+		if ((--a)->inmem) {
+			assert(a->align <= 4);
+			stk += a->size;
+			if (a->align == 4)
+				stk += stk & 15;
+		}
+	stk += stk & 15;
+
+	if (rtype(i1->arg[1]) == RTyp)
 		diag("struct-returning function not implemented");
-	if (stk)
-		emit(OSAlloc, 0, R, newcon(-(int64_t)stk, fn), R);
-	for (n=0; n<2; n++) {
-		r = TMP(ireg[n]);
-		emit(OCopy, 0, R, r, R);
-	}
+
 	emit(OCopy, i1->wide, i1->to, TMP(RAX), R);
-	emit(OCall, 0, R, i->arg[0], R);
-	emit(OCopy, 0, TMP(RAX), CON_Z, R);
-	if (stk % 16)
-		emit(OXPush, 1, R, TMP(RAX), R);
+#if 1
+	for (n=0; n<6; n++) {
+		emit(OCopy, 0, R, TMP(ireg[n]), R);
+	}
+#endif
+	r = newcon(-(int64_t)stk, fn);
+	emit(OSAlloc, 0, R, r, R);
+	emit(OCall, 0, TMP(RAX), i->arg[0], R);
 
 	for (i=i0, a=ai, ni=0; i<i1; i++, a++) {
 		if (a->inmem)
 			continue;
 		if (i->op == OArgc) {
-			diag("aggregate in registers not implemented");
+			if (a->size > 8) {
+				r = TMP(ireg[ni+1]);
+				r1 = newtmp(fn);
+				emit(OLoad, 1, r, r1, R);
+				r = newcon(8, fn);
+				emit(OAdd, 1, r1, i->arg[1], r);
+				r = TMP(ireg[ni]);
+				ni += 2;
+			} else
+				r = TMP(ireg[ni++]);
+			emit(OLoad, 1, r, i->arg[1], R);
 		} else {
 			r = TMP(ireg[ni++]);
 			emit(OCopy, i->wide, r, i->arg[0], R);
 		}
 	}
 
-	stk = 0;
 	for (i=i0, a=ai; i<i1; i++, a++) {
 		if (!a->inmem)
 			continue;
 		sz = a->size;
 		if (a->align == 4 && stk % 16)
 			sz += 8;
-		stk += sz;
+		stk -= sz;
 		if (i->op == OArgc) {
-			emit(OCopy, 0, R, TMP(RCX), R);
-			emit(OCopy, 0, R, TMP(RDI), R);
-			emit(OCopy, 0, R, TMP(RSI), R);
-			emit(OXMovs, 0, R, R, R);
-			emit(OCopy, 1, TMP(RCX), newcon(a->size, fn), R);
-			emit(OCopy, 1, TMP(RDI), TMP(RSP), R);
-			emit(OCopy, 1, TMP(RSI), i->arg[1], R);
-			emit(OSAlloc, 0, R, newcon(sz, fn), R);
+			assert(!"argc todo 2");
 		} else {
 			emit(OXPush, 1, R, i->arg[0], R);
 		}
 	}
+	if (stk) {
+		assert(stk == 8);
+		emit(OXPush, 1, R, CON_Z, R);
+	}
 
 	free(ai);
 }