summary refs log tree commit diff
path: root/arm64
diff options
context:
space:
mode:
Diffstat (limited to 'arm64')
-rw-r--r--arm64/emit.c65
-rw-r--r--arm64/isel.c31
2 files changed, 69 insertions, 27 deletions
diff --git a/arm64/emit.c b/arm64/emit.c
index 7316f78..292dc79 100644
--- a/arm64/emit.c
+++ b/arm64/emit.c
@@ -245,33 +245,50 @@ emitf(char *s, Ins *i, E *e)
 static void
 loadaddr(Con *c, char *rn, 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 *p, *l, off[32];
+	char *p, *l, *s;
+
+	switch (c->reloc) {
+	default:
+		die("unreachable");
+	case RelDef:
+		if (T.apple)
+			s = "\tadrp\tR, S@pageO\n"
+			    "\tadd\tR, R, S@pageoffO\n";
+		else
+			s = "\tadrp\tR, SO\n"
+			    "\tadd\tR, R, #:lo12:SO\n";
+		break;
+	case RelThr:
+		if (T.apple)
+			s = "\tadrp\tR, S@tlvppage\n"
+			    "\tldr\tR, [R, S@tlvppageoff]\n";
+		else
+			s = "\tmrs\tR, tpidr_el0\n"
+			    "\tadd\tR, R, #:tprel_hi12:SO, lsl #12\n"
+			    "\tadd\tR, R, #:tprel_lo12_nc:SO\n";
+		break;
+	}
 
-	if (c->bits.i)
-		/* todo, handle large offsets */
-		sprintf(off, "+%"PRIi64, c->bits.i);
-	else
-		off[0] = 0;
 	l = str(c->label);
 	p = l[0] == '"' ? "" : T.assym;
-	if (c->reloc == RelThr) {
-		fprintf(e->f, "\tmrs\t%s, tpidr_el0\n", rn);
-		fprintf(e->f, "\tadd\t%s, %s, #:tprel_hi12:%s%s%s, lsl #12\n",
-			rn, rn, p, l, off);
-		fprintf(e->f, "\tadd\t%s, %s, #:tprel_lo12_nc:%s%s%s\n",
-			rn, rn, p, l, off);
-	} else {
-		fprintf(e->f, ldsym[T.apple != 0][0], rn, p, l, off);
-		fprintf(e->f, ldsym[T.apple != 0][1], rn, rn, p, l, off);
-	}
+	for (; *s; s++)
+		switch (*s) {
+		default:
+			fputc(*s, e->f);
+			break;
+		case 'R':
+			fputs(rn, e->f);
+			break;
+		case 'S':
+			fputs(p, e->f);
+			fputs(l, e->f);
+			break;
+		case 'O':
+			if (c->bits.i)
+				/* todo, handle large offsets */
+				fprintf(e->f, "+%"PRIi64, c->bits.i);
+			break;
+		}
 }
 
 static void
diff --git a/arm64/isel.c b/arm64/isel.c
index 320cf33..a8d36fa 100644
--- a/arm64/isel.c
+++ b/arm64/isel.c
@@ -70,20 +70,45 @@ static void
 fixarg(Ref *pr, int k, int phi, Fn *fn)
 {
 	char buf[32];
-	Ref r0, r1, r2;
+	Ref r0, r1, r2, r3;
 	int s, n;
-	Con *c;
+	Con *c, cc;
 
 	r0 = *pr;
 	switch (rtype(r0)) {
 	case RCon:
+		c = &fn->con[r0.val];
+		if (T.apple
+		&& c->type == CAddr
+		&& c->reloc == RelThr) {
+			r1 = newtmp("isel", Kl, fn);
+			*pr = r1;
+			if (c->bits.i) {
+				r2 = newtmp("isel", Kl, fn);
+				cc = (Con){.type = CBits};
+				cc.bits.i = c->bits.i;
+				r3 = newcon(&cc, fn);
+				emit(Oadd, Kl, r1, r2, r3);
+				r1 = r2;
+			}
+			emit(Ocopy, Kl, r1, TMP(R0), R);
+			r1 = newtmp("isel", Kl, fn);
+			r2 = newtmp("isel", Kl, fn);
+			emit(Ocall, 0, R, r1, CALL(33));
+			emit(Ocopy, Kl, TMP(R0), r2, R);
+			emit(Oload, Kl, r1, r2, R);
+			cc = *c;
+			cc.bits.i = 0;
+			r3 = newcon(&cc, fn);
+			emit(Ocopy, Kl, r2, r3, R);
+			break;
+		}
 		if (KBASE(k) == 0 && phi)
 			return;
 		r1 = newtmp("isel", k, fn);
 		if (KBASE(k) == 0) {
 			emit(Ocopy, k, r1, r0, R);
 		} else {
-			c = &fn->con[r0.val];
 			n = stashbits(&c->bits, KWIDE(k) ? 8 : 4);
 			vgrow(&fn->con, ++fn->ncon);
 			c = &fn->con[fn->ncon-1];