summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--all.h5
-rw-r--r--parse.c3
-rw-r--r--sysv.c86
-rw-r--r--test/abi5.ssa13
4 files changed, 67 insertions, 40 deletions
diff --git a/all.h b/all.h
index b6392e5..39c85f1 100644
--- a/all.h
+++ b/all.h
@@ -429,13 +429,14 @@ struct Typ {
 
 	struct Seg {
 		enum {
+			Send,
 			Spad,
 			Sint,
 			Sflt,
 			Styp,
 		};
-		uint type:2;
-		uint len:30; /* index in typ[] for Styp */
+		uint type:3;
+		uint len:29; /* index in typ[] for Styp */
 	} (*seg)[NSeg+1];
 };
 
diff --git a/parse.c b/parse.c
index 7afa977..31a6d09 100644
--- a/parse.c
+++ b/parse.c
@@ -847,8 +847,7 @@ parseseg(Seg *seg, Typ *ty, int t)
 	}
 	if (t != Trbrace)
 		err(", or } expected");
-	seg[n].type = Sint;
-	seg[n].len = 0;
+	seg[n].type = Send;
 	a = 1 << al;
 	sz = (sz + a - 1) & -a;
 	if (sz >= ty->size)
diff --git a/sysv.c b/sysv.c
index 7e5b819..5a82f8e 100644
--- a/sysv.c
+++ b/sysv.c
@@ -17,11 +17,44 @@ struct RAlloc {
 };
 
 static void
-aclass(AClass *a, Typ *t)
+classify(AClass *a, Typ *t, int *pn, int *pe)
 {
-	int e, s, n, cls;
-	uint sz, al;
 	Seg *seg;
+	int n, s, *cls;
+
+	for (n=0; n<t->nunion; n++) {
+		seg = t->seg[n];
+		for (s=0; *pe<2; (*pe)++) {
+			cls = &a->cls[*pe];
+			for (; *pn<8 && seg[s].type!=Send; s++) {
+				switch (seg[s].type) {
+				case Spad:
+					/* don't change anything */
+					break;
+				case Sflt:
+					if (*cls == Kx)
+						*cls = Kd;
+					break;
+				case Sint:
+					*cls = Kl;
+					break;
+				case Styp:
+					classify(a, &typ[seg[s].len], pn, pe);
+					continue;
+				}
+				*pn += seg[s].len;
+			}
+			assert(*pn <= 8);
+			*pn = 0;
+		}
+	}
+}
+
+static void
+typclass(AClass *a, Typ *t)
+{
+	int e, n;
+	uint sz, al;
 
 	sz = t->size;
 	al = 1u << t->align;
@@ -46,31 +79,12 @@ aclass(AClass *a, Typ *t)
 		return;
 	}
 
-	seg = t->seg[0];
+	a->cls[0] = Kx;
+	a->cls[1] = Kx;
 	a->inmem = 0;
-	for (e=0, s=0; e<2; e++) {
-		cls = -1;
-		for (n=0; n<8 && seg[s].len; s++) {
-			switch (seg[s].type) {
-			case Spad:
-				/* don't change anything */
-				break;
-			case Sflt:
-				if (cls == -1)
-					cls = Kd;
-				break;
-			case Sint:
-				cls = Kl;
-				break;
-			case Styp:
-				assert(!"todo");
-				break;
-			}
-			n += seg[s].len;
-		}
-		assert(n <= 8);
-		a->cls[e] = cls;
-	}
+	n = 0;
+	e = 0;
+	classify(a, t, &n, &e);
 }
 
 static void
@@ -124,7 +138,7 @@ selret(Blk *b, Fn *fn)
 	b->jmp.type = Jret0;
 
 	if (j == Jretc) {
-		aclass(&aret, &typ[fn->retty]);
+		typclass(&aret, &typ[fn->retty]);
 		if (aret.inmem) {
 			assert(rtype(fn->retr) == RTmp);
 			emit(Ocopy, Kl, TMP(RAX), fn->retr, R);
@@ -154,7 +168,7 @@ selret(Blk *b, Fn *fn)
 }
 
 static int
-classify(Ins *i0, Ins *i1, AClass *ac, int op, AClass *aret)
+argsclass(Ins *i0, Ins *i1, AClass *ac, int op, AClass *aret)
 {
 	int nint, ni, nsse, ns, n, *pn;
 	AClass *a;
@@ -181,7 +195,7 @@ classify(Ins *i0, Ins *i1, AClass *ac, int op, AClass *aret)
 			a->cls[0] = i->cls;
 		} else {
 			n = i->arg[0].val;
-			aclass(a, &typ[n]);
+			typclass(a, &typ[n]);
 			if (a->inmem)
 				continue;
 			ni = ns = 0;
@@ -279,10 +293,10 @@ selcall(Fn *fn, Ins *i0, Ins *i1, RAlloc **rap)
 	ac = alloc((i1-i0) * sizeof ac[0]);
 	if (!req(i1->arg[1], R)) {
 		assert(rtype(i1->arg[1]) == RType);
-		aclass(&aret, &typ[i1->arg[1].val]);
-		ca = classify(i0, i1, ac, Oarg, &aret);
+		typclass(&aret, &typ[i1->arg[1].val]);
+		ca = argsclass(i0, i1, ac, Oarg, &aret);
 	} else
-		ca = classify(i0, i1, ac, Oarg, 0);
+		ca = argsclass(i0, i1, ac, Oarg, 0);
 
 	for (stk=0, a=&ac[i1-i0]; a>ac;)
 		if ((--a)->inmem) {
@@ -393,10 +407,10 @@ selpar(Fn *fn, Ins *i0, Ins *i1)
 	ni = ns = 0;
 
 	if (fn->retty >= 0) {
-		aclass(&aret, &typ[fn->retty]);
-		classify(i0, i1, ac, Opar, &aret);
+		typclass(&aret, &typ[fn->retty]);
+		argsclass(i0, i1, ac, Opar, &aret);
 	} else
-		classify(i0, i1, ac, Opar, 0);
+		argsclass(i0, i1, ac, Opar, 0);
 
 	for (i=i0, a=ac; i<i1; i++, a++) {
 		if (i->op != Oparc || a->inmem)
diff --git a/test/abi5.ssa b/test/abi5.ssa
index 7899035..c3d9046 100644
--- a/test/abi5.ssa
+++ b/test/abi5.ssa
@@ -8,6 +8,8 @@ type :st5 = { s, l }
 type :st6 = { b 16 }
 type :st7 = { s, d }
 type :st8 = { w 4 }
+type :un9 = { { b } { s } }
+type :st9 = { w, :un9 }
 
 data $fmt1 = { b "t1: %s\n", b 0 }
 data $fmt2 = { b "t2: %d\n", b 0 }
@@ -17,6 +19,7 @@ data $fmt5 = { b "t5: %f %lld\n", b 0 }
 data $fmt6 = { b "t6: %s\n", b 0 }
 data $fmt7 = { b "t7: %f %f\n", b 0 }
 data $fmt8 = { b "t8: %d %d %d %d\n", b 0 }
+data $fmt9 = { b "t9: %d %f\n", b 0 }
 
 export
 function $test() {
@@ -68,6 +71,13 @@ function $test() {
 	%w84 =w loadw %r812
 	%i8 =w call $printf(l $fmt8, w %w81, w %w82, w %w83, w %w84)
 
+	%r9 =:st9 call $t9()
+	%r94 =l add 4, %r9
+	%w9 =w loadw %r9
+	%s9 =s loads %r94
+	%d9 =d exts %s9
+	%i9 =w call $printf(l $fmt9, w %w9, d %d9)
+
 	ret
 }
 
@@ -82,6 +92,7 @@ function $test() {
 # typedef struct { char t[16]; } st6;
 # typedef struct { float f; double d; } st7;
 # typedef struct { int i[4]; } st8;
+# typedef struct { int i; union { char c; float f; } u; } st9;
 # extern void test(void);
 # st1 t1() { return (st1){"abcdefghijklmnop"}; }
 # st2 t2() { return (st2){2}; }
@@ -91,6 +102,7 @@ function $test() {
 # st6 t6() { return (st6){"abcdefghijklmno"}; }
 # st7 t7() { return (st7){7.77,77.7}; }
 # st8 t8() { return (st8){-8,88,-888,8888}; }
+# st9 t9() { return (st9){9,{.f=9.9}}; }
 # int main() { test(); return 0; }
 # <<<
 
@@ -103,4 +115,5 @@ function $test() {
 # t6: abcdefghijklmno
 # t7: 7.770000 77.700000
 # t8: -8 88 -888 8888
+# t9: 9 9.900000
 # <<<