summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--arm64/abi.c57
1 files changed, 26 insertions, 31 deletions
diff --git a/arm64/abi.c b/arm64/abi.c
index 0e4b941..396c704 100644
--- a/arm64/abi.c
+++ b/arm64/abi.c
@@ -41,13 +41,15 @@ static int fpreg[12] = {V0, V1, V2, V3, V4, V5, V6, V7};
 
 /* layout of call's second argument (RCall)
  *
- *  29   13    9    5   2  0
- *  |0.00|x|xxxx|xxxx|xxx|xx|                  range
- *        |    |    |   |  ` gp regs returned (0..2)
- *        |    |    |   ` fp regs returned    (0..4)
- *        |    |    ` gp regs passed          (0..8)
- *        |     ` fp regs passed              (0..8)
- *        ` is x8 used                        (0..1)
+ *         13
+ *  29   14 |    9    5   2  0
+ *  |0.00|x|x|xxxx|xxxx|xxx|xx|                  range
+ *        | |    |    |   |  ` gp regs returned (0..2)
+ *        | |    |    |   ` fp regs returned    (0..4)
+ *        | |    |    ` gp regs passed          (0..8)
+ *        | |     ` fp regs passed              (0..8)
+ *        | ` indirect result register x8 used  (0..1)
+ *        ` env pointer passed in x9            (0..1)
  */
 
 static int
@@ -202,12 +204,13 @@ selret(Blk *b, Fn *fn)
 }
 
 static int
-argsclass(Ins *i0, Ins *i1, Class *carg, Ref *env)
+argsclass(Ins *i0, Ins *i1, Class *carg)
 {
-	int ngp, nfp, *gp, *fp;
+	int envc, ngp, nfp, *gp, *fp;
 	Class *c;
 	Ins *i;
 
+	envc = 0;
 	gp = gpreg;
 	fp = fpreg;
 	ngp = 8;
@@ -247,10 +250,10 @@ argsclass(Ins *i0, Ins *i1, Class *carg, Ref *env)
 			c->class |= Cstk;
 			break;
 		case Opare:
-			*env = i->to;
-			break;
 		case Oarge:
-			*env = i->arg[0];
+			*c->reg = R9;
+			*c->cls = Kl;
+			envc = 1;
 			break;
 		case Oargv:
 			break;
@@ -258,7 +261,7 @@ argsclass(Ins *i0, Ins *i1, Class *carg, Ref *env)
 			die("unreachable");
 		}
 
-	return ((gp-gpreg) << 5) | ((fp-fpreg) << 9);
+	return envc << 14 | (gp-gpreg) << 5 | (fp-fpreg) << 9;
 }
 
 bits
@@ -286,14 +289,15 @@ bits
 arm64_argregs(Ref r, int p[2])
 {
 	bits b;
-	int ngp, nfp, x8;
+	int ngp, nfp, x8, x9;
 
 	assert(rtype(r) == RCall);
 	ngp = (r.val >> 5) & 15;
 	nfp = (r.val >> 9) & 15;
 	x8 = (r.val >> 13) & 1;
+	x9 = (r.val >> 14) & 1;
 	if (p) {
-		p[0] = ngp + x8;
+		p[0] = ngp + x8 + x9;
 		p[1] = nfp;
 	}
 	b = 0;
@@ -301,7 +305,7 @@ arm64_argregs(Ref r, int p[2])
 		b |= BIT(R0+ngp);
 	while (nfp--)
 		b |= BIT(V0+nfp);
-	return b | ((bits)x8 << R8);
+	return b | ((bits)x8 << R8) | ((bits)x9 << R9);
 }
 
 static void
@@ -326,14 +330,13 @@ selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
 {
 	Ins *i;
 	Class *ca, *c, cr;
-	int cty, envc;
+	int cty;
 	uint n;
 	uint64_t stk, off;
-	Ref r, rstk, env, tmp[4];
+	Ref r, rstk, tmp[4];
 
-	env = R;
 	ca = alloc((i1-i0) * sizeof ca[0]);
-	cty = argsclass(i0, i1, ca, &env);
+	cty = argsclass(i0, i1, ca);
 
 	stk = 0;
 	for (i=i0, c=ca; i<i1; i++, c++) {
@@ -380,10 +383,6 @@ selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
 
 	emit(Ocall, 0, R, i1->arg[0], CALL(cty));
 
-	envc = !req(R, env);
-	if (envc)
-		die("todo: env calls");
-
 	if (cty & (1 << 13))
 		/* struct return argument */
 		emit(Ocopy, Kl, TMP(R8), i1->to, R);
@@ -391,7 +390,7 @@ 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)
+		if (i->op == Oarg || i->op == Oarge)
 			emit(Ocopy, *c->cls, TMP(*c->reg), i->arg[0], R);
 		if (i->op == Oargc)
 			ldregs(c->reg, c->cls, c->nreg, i->arg[1], fn);
@@ -426,13 +425,12 @@ selpar(Fn *fn, Ins *i0, Ins *i1)
 	Insl *il;
 	Ins *i;
 	int n, s, cty;
-	Ref r, env, tmp[16], *t;
+	Ref r, tmp[16], *t;
 
-	env = R;
 	ca = alloc((i1-i0) * sizeof ca[0]);
 	curi = &insb[NIns];
 
-	cty = argsclass(i0, i1, ca, &env);
+	cty = argsclass(i0, i1, ca);
 	fn->reg = arm64_argregs(CALL(cty), 0);
 
 	il = 0;
@@ -475,9 +473,6 @@ selpar(Fn *fn, Ins *i0, Ins *i1)
 			emit(Ocopy, *c->cls, i->to, TMP(*c->reg), R);
 		}
 
-	if (!req(R, env))
-		die("todo: env calls");
-
 	return (Params){
 		.nstk = s - 2,
 		.ngp = (cty >> 5) & 15,