summary refs log tree commit diff
path: root/arm64/abi.c
diff options
context:
space:
mode:
authorQuentin Carbonneaux <quentin@c9x.me>2022-08-31 21:29:15 +0200
committerQuentin Carbonneaux <quentin@c9x.me>2022-10-03 10:41:26 +0200
commit79f3673d205617ac567f0566ebf8f450932d9976 (patch)
tree48ea32843eacd8ac33b4bbcdc975df5d8ab6356c /arm64/abi.c
parentbda9f2833c39ea5f4266dbcb4506ed8895e22d3f (diff)
downloadroux-79f3673d205617ac567f0566ebf8f450932d9976.tar.gz
new arm64_apple target
Should make qbe work on apple
arm-based hardware.
Diffstat (limited to 'arm64/abi.c')
-rw-r--r--arm64/abi.c232
1 files changed, 194 insertions, 38 deletions
diff --git a/arm64/abi.c b/arm64/abi.c
index b2b5973..945a676 100644
--- a/arm64/abi.c
+++ b/arm64/abi.c
@@ -1,5 +1,6 @@
 #include "all.h"
 
+typedef struct Abi Abi;
 typedef struct Class Class;
 typedef struct Insl Insl;
 typedef struct Params Params;
@@ -9,6 +10,12 @@ enum {
 	Cptr = 2, /* replaced by a pointer */
 };
 
+struct Abi {
+	void (*vastart)(Fn *, Params, Ref);
+	void (*vaarg)(Fn *, Blk *, Ins *);
+	int apple;
+};
+
 struct Class {
 	char class;
 	char ishfa;
@@ -17,6 +24,7 @@ struct Class {
 		uchar size;
 	} hfa;
 	uint size;
+	uint align;
 	Typ *t;
 	uchar nreg;
 	uchar ngp;
@@ -33,11 +41,15 @@ struct Insl {
 struct Params {
 	uint ngp;
 	uint nfp;
-	uint nstk;
+	uint stk;
 };
 
 static int gpreg[12] = {R0, R1, R2, R3, R4, R5, R6, R7};
 static int fpreg[12] = {V0, V1, V2, V3, V4, V5, V6, V7};
+static int store[] = {
+	[Kw] = Ostorew, [Kl] = Ostorel,
+	[Ks] = Ostores, [Kd] = Ostored
+};
 
 /* layout of call's second argument (RCall)
  *
@@ -92,9 +104,10 @@ typclass(Class *c, Typ *t, int *gp, int *fp)
 	c->class = 0;
 	c->ngp = 0;
 	c->nfp = 0;
+	c->align = 8;
 
-	if (t->align > 4)
-		err("alignments larger than 16 are not supported");
+	if (t->align > 3)
+		err("alignments larger than 8 are not supported");
 
 	if (t->isdark || sz > 16 || sz == 0) {
 		/* large structs are replaced by a
@@ -130,10 +143,6 @@ typclass(Class *c, Typ *t, int *gp, int *fp)
 static void
 sttmps(Ref tmp[], int cls[], uint nreg, Ref mem, Fn *fn)
 {
-	static int st[] = {
-		[Kw] = Ostorew, [Kl] = Ostorel,
-		[Ks] = Ostores, [Kd] = Ostored
-	};
 	uint n;
 	uint64_t off;
 	Ref r;
@@ -143,7 +152,7 @@ sttmps(Ref tmp[], int cls[], uint nreg, Ref mem, Fn *fn)
 	for (n=0; n<nreg; n++) {
 		tmp[n] = newtmp("abi", cls[n], fn);
 		r = newtmp("abi", Kl, fn);
-		emit(st[cls[n]], 0, R, tmp[n], r);
+		emit(store[cls[n]], 0, R, tmp[n], r);
 		emit(Oadd, Kl, r, mem, getcon(off, fn));
 		off += KWIDE(cls[n]) ? 8 : 4;
 	}
@@ -206,12 +215,13 @@ selret(Blk *b, Fn *fn)
 }
 
 static int
-argsclass(Ins *i0, Ins *i1, Class *carg)
+argsclass(Ins *i0, Ins *i1, Class *carg, int apple)
 {
-	int envc, ngp, nfp, *gp, *fp;
+	int va, envc, ngp, nfp, *gp, *fp;
 	Class *c;
 	Ins *i;
 
+	va = 0;
 	envc = 0;
 	gp = gpreg;
 	fp = fpreg;
@@ -219,10 +229,32 @@ argsclass(Ins *i0, Ins *i1, Class *carg)
 	nfp = 8;
 	for (i=i0, c=carg; i<i1; i++, c++)
 		switch (i->op) {
+		case Oargsb:
+		case Oargub:
+		case Oparsb:
+		case Oparub:
+			c->size = 1;
+			goto Scalar;
+		case Oargsh:
+		case Oarguh:
+		case Oparsh:
+		case Oparuh:
+			c->size = 2;
+			goto Scalar;
 		case Opar:
 		case Oarg:
-			*c->cls = i->cls;
 			c->size = 8;
+			if (apple && !KWIDE(i->cls))
+				c->size = 4;
+		Scalar:
+			c->align = c->size;
+			*c->cls = i->cls;
+			if (va) {
+				c->class |= Cstk;
+				c->size = 8;
+				c->align = 8;
+				break;
+			}
 			if (KBASE(i->cls) == 0 && ngp > 0) {
 				ngp--;
 				*c->reg = *gp++;
@@ -258,6 +290,7 @@ argsclass(Ins *i0, Ins *i1, Class *carg)
 			envc = 1;
 			break;
 		case Oargv:
+			va = apple != 0;
 			break;
 		default:
 			die("unreachable");
@@ -327,18 +360,23 @@ stkblob(Ref r, Class *c, Fn *fn, Insl **ilp)
 	*ilp = il;
 }
 
+static uint
+align(uint x, uint al)
+{
+	return (x + al-1) & -al;
+}
+
 static void
-selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
+selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp, int apple)
 {
 	Ins *i;
 	Class *ca, *c, cr;
-	int cty;
-	uint n;
-	uint64_t stk, off;
+	int op, cty;
+	uint n, stk, off;;
 	Ref r, rstk, tmp[4];
 
 	ca = alloc((i1-i0) * sizeof ca[0]);
-	cty = argsclass(i0, i1, ca);
+	cty = argsclass(i0, i1, ca, apple);
 
 	stk = 0;
 	for (i=i0, c=ca; i<i1; i++, c++) {
@@ -347,10 +385,12 @@ selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
 			stkblob(i->arg[0], c, fn, ilp);
 			i->op = Oarg;
 		}
-		if (c->class & Cstk)
+		if (c->class & Cstk) {
+			stk = align(stk, c->align);
 			stk += c->size;
+		}
 	}
-	stk += stk & 15;
+	stk = align(stk, 16);
 	rstk = getcon(stk, fn);
 	if (stk)
 		emit(Oadd, Kl, TMP(SP), TMP(SP), rstk);
@@ -403,9 +443,16 @@ selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
 	for (i=i0, c=ca; i<i1; i++, c++) {
 		if ((c->class & Cstk) == 0)
 			continue;
-		if (i->op == Oarg) {
+		off = align(off, c->align);
+		if (i->op == Oarg || isargbh(i->op)) {
 			r = newtmp("abi", Kl, fn);
-			emit(Ostorel, 0, R, i->arg[0], r);
+			switch (c->size) {
+			case 1: op = Ostoreb; break;
+			case 2: op = Ostoreh; break;
+			case 4:
+			case 8: op = store[*c->cls]; break;
+			}
+			emit(op, 0, R, i->arg[0], r);
 			emit(Oadd, Kl, r, TMP(SP), getcon(off, fn));
 		}
 		if (i->op == Oargc)
@@ -421,18 +468,19 @@ selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
 }
 
 static Params
-selpar(Fn *fn, Ins *i0, Ins *i1)
+selpar(Fn *fn, Ins *i0, Ins *i1, int apple)
 {
 	Class *ca, *c, cr;
 	Insl *il;
 	Ins *i;
-	int n, s, cty;
+	int op, n, cty;
+	uint off;
 	Ref r, tmp[16], *t;
 
 	ca = alloc((i1-i0) * sizeof ca[0]);
 	curi = &insb[NIns];
 
-	cty = argsclass(i0, i1, ca);
+	cty = argsclass(i0, i1, ca, apple);
 	fn->reg = arm64_argregs(CALL(cty), 0);
 
 	il = 0;
@@ -457,26 +505,32 @@ selpar(Fn *fn, Ins *i0, Ins *i1)
 	}
 
 	t = tmp;
-	s = 2;
+	off = 0;
 	for (i=i0, c=ca; i<i1; i++, c++)
 		if (i->op == Oparc && !(c->class & Cptr)) {
 			if (c->class & Cstk) {
-				fn->tmp[i->to.val].slot = -s;
-				s += c->size / 8;
+				off = align(off, c->align);
+				fn->tmp[i->to.val].slot = -(off+2);
+				off += c->size;
 			} else
 				for (n=0; n<c->nreg; n++) {
 					r = TMP(c->reg[n]);
 					emit(Ocopy, c->cls[n], *t++, r, R);
 				}
 		} else if (c->class & Cstk) {
-			emit(Oload, *c->cls, i->to, SLOT(-s), R);
-			s++;
+			off = align(off, c->align);
+			if (isparbh(i->op))
+				op = Oloadsb + (i->op - Oparsb);
+			else
+				op = Oload;
+			emit(op, *c->cls, i->to, SLOT(-(off+2)), R);
+			off += c->size;
 		} else {
 			emit(Ocopy, *c->cls, i->to, TMP(*c->reg), R);
 		}
 
 	return (Params){
-		.nstk = s - 2,
+		.stk = align(off, 8),
 		.ngp = (cty >> 5) & 15,
 		.nfp = (cty >> 9) & 15
 	};
@@ -514,7 +568,24 @@ chpred(Blk *b, Blk *bp, Blk *bp1)
 }
 
 static void
-selvaarg(Fn *fn, Blk *b, Ins *i)
+apple_selvaarg(Fn *fn, Blk *b, Ins *i)
+{
+	Ref ap, stk, stk8, c8;
+
+	(void)b;
+	c8 = getcon(8, fn);
+	ap = i->arg[0];
+	stk8 = newtmp("abi", Kl, fn);
+	stk = newtmp("abi", Kl, fn);
+
+	emit(Ostorel, 0, R, stk8, ap);
+	emit(Oadd, Kl, stk8, stk, c8);
+	emit(Oload, i->cls, i->to, stk, R);
+	emit(Oload, Kl, stk, ap, R);
+}
+
+static void
+arm64_selvaarg(Fn *fn, Blk *b, Ins *i)
 {
 	Ref loc, lreg, lstk, nr, r0, r1, c8, c16, c24, c28, ap;
 	Blk *b0, *bstk, *breg;
@@ -607,7 +678,21 @@ selvaarg(Fn *fn, Blk *b, Ins *i)
 }
 
 static void
-selvastart(Fn *fn, Params p, Ref ap)
+apple_selvastart(Fn *fn, Params p, Ref ap)
+{
+	Ref off, stk, arg;
+
+	off = getcon(p.stk, fn);
+	stk = newtmp("abi", Kl, fn);
+	arg = newtmp("abi", Kl, fn);
+
+	emit(Ostorel, 0, R, arg, ap);
+	emit(Oadd, Kl, arg, stk, off);
+	emit(Oaddr, Kl, stk, SLOT(-1), R);
+}
+
+static void
+arm64_selvastart(Fn *fn, Params p, Ref ap)
 {
 	Ref r0, r1, rsave;
 
@@ -615,7 +700,7 @@ selvastart(Fn *fn, Params p, Ref ap)
 
 	r0 = newtmp("abi", Kl, fn);
 	emit(Ostorel, Kw, R, r0, ap);
-	emit(Oadd, Kl, r0, rsave, getcon(p.nstk*8 + 192, fn));
+	emit(Oadd, Kl, r0, rsave, getcon(p.stk + 192, fn));
 
 	r0 = newtmp("abi", Kl, fn);
 	r1 = newtmp("abi", Kl, fn);
@@ -639,8 +724,8 @@ selvastart(Fn *fn, Params p, Ref ap)
 	emit(Oadd, Kl, r0, ap, getcon(28, fn));
 }
 
-void
-arm64_abi(Fn *fn)
+static void
+abi(Fn *fn, Abi abi)
 {
 	Blk *b;
 	Ins *i, *i0, *ip;
@@ -655,7 +740,7 @@ arm64_abi(Fn *fn)
 	for (b=fn->start, i=b->ins; i<&b->ins[b->nins]; i++)
 		if (!ispar(i->op))
 			break;
-	p = selpar(fn, b->ins, i);
+	p = selpar(fn, b->ins, i, abi.apple);
 	n = b->nins - (i - b->ins) + (&insb[NIns] - curi);
 	i0 = alloc(n * sizeof(Ins));
 	ip = icpy(ip = i0, curi, &insb[NIns] - curi);
@@ -682,14 +767,14 @@ arm64_abi(Fn *fn)
 				for (i0=i; i0>b->ins; i0--)
 					if (!isarg((i0-1)->op))
 						break;
-				selcall(fn, i0, i, &il);
+				selcall(fn, i0, i, &il, abi.apple);
 				i = i0;
 				break;
 			case Ovastart:
-				selvastart(fn, p, i->arg[0]);
+				abi.vastart(fn, p, i->arg[0]);
 				break;
 			case Ovaarg:
-				selvaarg(fn, b, i);
+				abi.vaarg(fn, b, i);
 				break;
 			case Oarg:
 			case Oargc:
@@ -707,3 +792,74 @@ arm64_abi(Fn *fn)
 		printfn(fn, stderr);
 	}
 }
+
+void
+arm64_abi(Fn *fn)
+{
+	abi(fn, (Abi){
+		arm64_selvastart,
+		arm64_selvaarg,
+		0
+	});
+}
+
+void
+apple_abi(Fn *fn)
+{
+	abi(fn, (Abi){
+		apple_selvastart,
+		apple_selvaarg,
+		1
+	});
+}
+
+/* abi0 for apple target; introduces
+ * necessery sign extension for arg
+ * passing & returns
+ */
+void
+apple_extsb(Fn *fn)
+{
+	Blk *b;
+	Ins *i0, *i1, *i;
+	int j, op;
+	Ref r;
+
+	for (b=fn->start; b; b=b->link) {
+		curi = &insb[NIns];
+		j = b->jmp.type;
+		if (isretbh(j)) {
+			r = newtmp("abi", Kw, fn);
+			op = Oextsb + (j - Jretsb);
+			emit(op, Kw, r, b->jmp.arg, R);
+			b->jmp.arg = r;
+		}
+		for (i=&b->ins[b->nins]; i>b->ins;) {
+			emiti(*--i);
+			if (i->op != Ocall)
+				continue;
+			for (i0=i1=i; i0>b->ins; i0--)
+				if (!isarg((i0-1)->op))
+					break;
+			for (i=i1; i>i0;) {
+				emiti(*--i);
+				if (isargbh(i->op)) {
+					i->to = newtmp("abi", Kl, fn);
+					curi->arg[0] = i->to;
+				}
+			}
+			for (i=i1; i>i0;)
+				if (isargbh((--i)->op)) {
+					op = Oextsb + (i->op - Oargsb);
+					emit(op, Kw, i->to, i->arg[0], R);
+				}
+		}
+		b->nins = &insb[NIns] - curi;
+		idup(&b->ins, curi, b->nins);
+	}
+
+	if (debug['A']) {
+		fprintf(stderr, "\n> After apple_extsb:\n");
+		printfn(fn, stderr);
+	}
+}