summary refs log tree commit diff
path: root/arm64
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
parentbda9f2833c39ea5f4266dbcb4506ed8895e22d3f (diff)
downloadroux-79f3673d205617ac567f0566ebf8f450932d9976.tar.gz
new arm64_apple target
Should make qbe work on apple
arm-based hardware.
Diffstat (limited to 'arm64')
-rw-r--r--arm64/abi.c232
-rw-r--r--arm64/all.h3
-rw-r--r--arm64/emit.c58
-rw-r--r--arm64/targ.c38
4 files changed, 261 insertions, 70 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);
+	}
+}
diff --git a/arm64/all.h b/arm64/all.h
index ff2b3ff..6b7f43e 100644
--- a/arm64/all.h
+++ b/arm64/all.h
@@ -28,6 +28,8 @@ extern int arm64_rclob[];
 bits arm64_retregs(Ref, int[2]);
 bits arm64_argregs(Ref, int[2]);
 void arm64_abi(Fn *);
+void apple_extsb(Fn *);
+void apple_abi(Fn *);
 
 /* isel.c */
 int arm64_logimm(uint64_t, int);
@@ -35,3 +37,4 @@ void arm64_isel(Fn *);
 
 /* emit.c */
 void arm64_emitfn(Fn *, FILE *);
+void apple_emitfn(Fn *, FILE *);
diff --git a/arm64/emit.c b/arm64/emit.c
index 55f5ce6..18c19d2 100644
--- a/arm64/emit.c
+++ b/arm64/emit.c
@@ -7,6 +7,7 @@ struct E {
 	Fn *fn;
 	uint64_t frame;
 	uint padding;
+	int apple;
 };
 
 #define CMP(X) \
@@ -144,10 +145,10 @@ slot(int s, E *e)
 	if (s == -1)
 		return 16 + e->frame;
 	if (s < 0) {
-		if (e->fn->vararg)
-			return 16 + e->frame + 192 - (s+2)*8;
+		if (e->fn->vararg && !e->apple)
+			return 16 + e->frame + 192 - (s+2);
 		else
-			return 16 + e->frame - (s+2)*8;
+			return 16 + e->frame - (s+2);
 	} else
 		return 16 + e->padding + 4 * s;
 }
@@ -243,8 +244,16 @@ emitf(char *s, Ins *i, E *e)
 }
 
 static void
-loadcon(Con *c, int r, int k, FILE *f)
+loadcon(Con *c, int r, int k, E *e)
 {
+	static char *ldsym[][2] = {
+		/* arm64 */
+		[0][0] = "\tadrp\t%s, %s%s%s\n",
+		[0][1] = "\tadd\t%s, %s, #:lo12:%s%s%s\n",
+		/* apple */
+		[1][0] = "\tadrp\t%s, %s%s@page%s\n",
+		[1][1] = "\tadd\t%s, %s, %s%s@pageoff%s\n",
+	};
 	char *rn, *l, *p, off[32];
 	int64_t n;
 	int w, sh;
@@ -261,24 +270,22 @@ loadcon(Con *c, int r, int k, FILE *f)
 			off[0] = 0;
 		l = str(c->label);
 		p = c->local ? T.asloc : l[0] == '"' ? "" : T.assym;
-		fprintf(f, "\tadrp\t%s, %s%s%s\n",
-			rn, p, l, off);
-		fprintf(f, "\tadd\t%s, %s, #:lo12:%s%s%s\n",
-			rn, rn, p, l, off);
+		fprintf(e->f, ldsym[e->apple][0], rn, p, l, off);
+		fprintf(e->f, ldsym[e->apple][1], rn, rn, p, l, off);
 		return;
 	}
 	assert(c->type == CBits);
 	if (!w)
 		n = (int32_t)n;
 	if ((n | 0xffff) == -1 || arm64_logimm(n, k)) {
-		fprintf(f, "\tmov\t%s, #%"PRIi64"\n", rn, n);
+		fprintf(e->f, "\tmov\t%s, #%"PRIi64"\n", rn, n);
 	} else {
-		fprintf(f, "\tmov\t%s, #%d\n",
+		fprintf(e->f, "\tmov\t%s, #%d\n",
 			rn, (int)(n & 0xffff));
 		for (sh=16; n>>=16; sh+=16) {
 			if ((!w && sh == 32) || sh == 64)
 				break;
-			fprintf(f, "\tmovk\t%s, #0x%x, lsl #%d\n",
+			fprintf(e->f, "\tmovk\t%s, #0x%x, lsl #%d\n",
 				rn, (uint)(n & 0xffff), sh);
 		}
 	}
@@ -358,7 +365,7 @@ emitins(Ins *i, E *e)
 		switch (rtype(i->arg[0])) {
 		case RCon:
 			c = &e->fn->con[i->arg[0].val];
-			loadcon(c, i->to.val, i->cls, e->f);
+			loadcon(c, i->to.val, i->cls, e);
 			break;
 		case RSlot:
 			i->op = Oload;
@@ -450,8 +457,8 @@ framelayout(E *e)
 
 */
 
-void
-arm64_emitfn(Fn *fn, FILE *out)
+static void
+emitfn(E *e)
 {
 	static char *ctoa[] = {
 	#define X(c, s) [c] = s,
@@ -463,13 +470,11 @@ arm64_emitfn(Fn *fn, FILE *out)
 	uint64_t o;
 	Blk *b, *t;
 	Ins *i;
-	E *e;
 
-	emitlnk(fn->name, &fn->lnk, ".text", out);
-	e = &(E){.f = out, .fn = fn};
+	emitlnk(e->fn->name, &e->fn->lnk, ".text", e->f);
 	framelayout(e);
 
-	if (e->fn->vararg) {
+	if (e->fn->vararg && !e->apple) {
 		for (n=7; n>=0; n--)
 			fprintf(e->f, "\tstr\tq%d, [sp, -16]!\n", n);
 		for (n=7; n>=0; n-=2)
@@ -531,7 +536,7 @@ arm64_emitfn(Fn *fn, FILE *out)
 			if (e->fn->dynalloc)
 				fputs("\tmov sp, x29\n", e->f);
 			o = e->frame + 16;
-			if (e->fn->vararg)
+			if (e->fn->vararg && !e->apple)
 				o += 192;
 			if (o <= 504)
 				fprintf(e->f,
@@ -589,5 +594,18 @@ arm64_emitfn(Fn *fn, FILE *out)
 		}
 	}
 	id0 += e->fn->nblk;
-	elf_emitfnfin(e->fn->name, e->f);
+}
+
+void
+arm64_emitfn(Fn *fn, FILE *out)
+{
+	emitfn(&(E){.f = out, .fn = fn, .apple = 0});
+	elf_emitfnfin(fn->name, out);
+}
+
+void
+apple_emitfn(Fn *fn, FILE *out)
+{
+	fn->lnk.align = 4;
+	emitfn(&(E){.f = out, .fn = fn, .apple = 1});
 }
diff --git a/arm64/targ.c b/arm64/targ.c
index 6079236..88c40f1 100644
--- a/arm64/targ.c
+++ b/arm64/targ.c
@@ -25,25 +25,39 @@ arm64_memargs(int op)
 	return 0;
 }
 
+#define ARM64_COMMON \
+	.gpr0 = R0, \
+	.ngpr = NGPR, \
+	.fpr0 = V0, \
+	.nfpr = NFPR, \
+	.rglob = RGLOB, \
+	.nrglob = 3, \
+	.rsave = arm64_rsave, \
+	.nrsave = {NGPS, NFPS}, \
+	.retregs = arm64_retregs, \
+	.argregs = arm64_argregs, \
+	.memargs = arm64_memargs, \
+	.isel = arm64_isel, \
+
 Target T_arm64 = {
 	.name = "arm64",
-	.gpr0 = R0,
-	.ngpr = NGPR,
-	.fpr0 = V0,
-	.nfpr = NFPR,
-	.rglob = RGLOB,
-	.nrglob = 3,
-	.rsave = arm64_rsave,
-	.nrsave = {NGPS, NFPS},
-	.retregs = arm64_retregs,
-	.argregs = arm64_argregs,
-	.memargs = arm64_memargs,
 	.abi0 = elimsb,
 	.abi1 = arm64_abi,
-	.isel = arm64_isel,
 	.emitfn = arm64_emitfn,
 	.emitfin = elf_emitfin,
 	.asloc = ".L",
+	ARM64_COMMON
+};
+
+Target T_arm64_apple = {
+	.name = "arm64_apple",
+	.abi0 = apple_extsb,
+	.abi1 = apple_abi,
+	.emitfn = apple_emitfn,
+	.emitfin = macho_emitfin,
+	.asloc = "L",
+	.assym = "_",
+	ARM64_COMMON
 };
 
 MAKESURE(globals_are_not_arguments,