summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--arm64/emit.c16
-rw-r--r--arm64/isel.c21
2 files changed, 35 insertions, 2 deletions
diff --git a/arm64/emit.c b/arm64/emit.c
index ec4d350..694abf3 100644
--- a/arm64/emit.c
+++ b/arm64/emit.c
@@ -306,10 +306,11 @@ fixarg(Ref *pr, int sz, E *e)
 static void
 emitins(Ins *i, E *e)
 {
-	char *rn;
+	char *l, *p, *rn;
 	uint64_t s;
 	int o;
 	Ref r;
+	Con *c;
 
 	switch (i->op) {
 	default:
@@ -355,7 +356,8 @@ emitins(Ins *i, E *e)
 		assert(isreg(i->to));
 		switch (rtype(i->arg[0])) {
 		case RCon:
-			loadcon(&e->fn->con[i->arg[0].val], i->to.val, i->cls, e->f);
+			c = &e->fn->con[i->arg[0].val];
+			loadcon(c, i->to.val, i->cls, e->f);
 			break;
 		case RSlot:
 			i->op = Oload;
@@ -386,6 +388,16 @@ emitins(Ins *i, E *e)
 				rn, s & 0xFFFF, rn, s >> 16, rn, rn
 			);
 		break;
+	case Ocall:
+		if (rtype(i->arg[0]) != RCon)
+			goto Table;
+		c = &e->fn->con[i->arg[0].val];
+		if (c->type != CAddr || c->bits.i)
+			die("invalid call argument");
+		l = str(c->label);
+		p = l[0] == '"' ? "" : T.assym;
+		fprintf(e->f, "\tbl\t%s%s\n", p, l);
+		break;
 	case Osalloc:
 		emitf("sub sp, sp, %0", i, e);
 		if (!req(i->to, R))
diff --git a/arm64/isel.c b/arm64/isel.c
index f064321..c80e481 100644
--- a/arm64/isel.c
+++ b/arm64/isel.c
@@ -156,6 +156,22 @@ selcmp(Ref arg[2], int k, Fn *fn)
 	return swap;
 }
 
+static int
+callable(Ref r, Fn *fn)
+{
+	Con *c;
+
+	if (rtype(r) == RTmp)
+		return 1;
+	if (rtype(r) == RCon) {
+		c = &fn->con[r.val];
+		if (c->type == CAddr)
+		if (c->bits.i == 0)
+			return 1;
+	}
+	return 0;
+}
+
 static void
 sel(Ins i, Fn *fn)
 {
@@ -178,6 +194,11 @@ sel(Ins i, Fn *fn)
 			i0->op += cc;
 		return;
 	}
+	if (i.op == Ocall)
+	if (callable(i.arg[0], fn)) {
+		emiti(i);
+		return;
+	}
 	if (i.op != Onop) {
 		emiti(i);
 		iarg = curi->arg; /* fixarg() can change curi */