summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--all.h4
-rw-r--r--parse.c24
-rw-r--r--sysv.c66
-rw-r--r--tools/lexh.c2
4 files changed, 68 insertions, 28 deletions
diff --git a/all.h b/all.h
index a038612..887d680 100644
--- a/all.h
+++ b/all.h
@@ -264,8 +264,12 @@ enum Op {
 	/* function instructions */
 	Opar = NPubOp,
 	Oparc,
+	Opare,
+#define ispar(o) (Opar <= o && o <= Opare)
 	Oarg,
 	Oargc,
+	Oarge,
+#define isarg(o) (Oarg <= o && o <= Oarge)
 	Ocall,
 	Ovacall,
 
diff --git a/parse.c b/parse.c
index a61ff1b..b911993 100644
--- a/parse.c
+++ b/parse.c
@@ -60,9 +60,11 @@ OpDesc opdesc[NOp] = {
 	[Oxcmp]   = { "xcmp",     1, {A(w,l,s,d), A(w,l,s,d)}, 1, 0, 0 },
 	[Oxtest]  = { "xtest",    1, {A(w,l,e,e), A(w,l,e,e)}, 1, 0, 0 },
 	[Oaddr]   = { "addr",     0, {A(m,m,e,e), A(x,x,e,e)}, 0, 1, 0 },
-	[Opar]    = { "parn",     0, {A(x,x,x,x), A(x,x,x,x)}, 0, 0, 0 },
+	[Opar]    = { "par",      0, {A(x,x,x,x), A(x,x,x,x)}, 0, 0, 0 },
+	[Opare]   = { "pare",     0, {A(x,x,x,x), A(x,x,x,x)}, 0, 0, 0 },
 	[Oparc]   = { "parc",     0, {A(e,x,e,e), A(e,x,e,e)}, 0, 0, 0 },
 	[Oarg]    = { "arg",      0, {A(w,l,s,d), A(x,x,x,x)}, 0, 0, 0 },
+	[Oarge]   = { "arge",     0, {A(w,l,s,d), A(x,x,x,x)}, 0, 0, 0 },
 	[Oargc]   = { "argc",     0, {A(e,x,e,e), A(e,l,e,e)}, 0, 0, 0 },
 	[Ocall]   = { "call",     0, {A(m,m,m,m), A(x,x,x,x)}, 0, 0, 0 },
 	[Ovacall] = { "vacall",   0, {A(m,m,m,m), A(x,x,x,x)}, 0, 0, 0 },
@@ -108,6 +110,7 @@ enum {
 	Talloc2,
 
 	Tcall,
+	Tenv,
 	Tphi,
 	Tjmp,
 	Tjnz,
@@ -156,6 +159,7 @@ static char *kwmap[Ntok] = {
 	[Talloc1] = "alloc1",
 	[Talloc2] = "alloc2",
 	[Tcall] = "call",
+	[Tenv] = "env",
 	[Tphi] = "phi",
 	[Tjmp] = "jmp",
 	[Tjnz] = "jnz",
@@ -493,17 +497,25 @@ parsecls(int *tyn)
 static int
 parserefl(int arg)
 {
-	int k, ty;
+	int k, ty, env, hasenv;
 	Ref r;
 
+	hasenv = 0;
 	expect(Tlparen);
 	while (peek() != Trparen && peek() != Tdots) {
 		if (curi - insb >= NIns)
 			err("too many instructions (1)");
+		env = peek() == Tenv;
+		if (env)
+			next();
 		k = parsecls(&ty);
 		r = parseref();
 		if (req(r, R))
-			err("invalid reference argument");
+			err("invalid argument");
+		if (hasenv && env)
+			err("only one environment allowed");
+		if (env && k != Kl)
+			err("environment must be of type l");
 		if (!arg && rtype(r) != RTmp)
 			err("invalid function parameter");
 		if (k == 4)
@@ -511,12 +523,18 @@ parserefl(int arg)
 				*curi = (Ins){Oargc, R, {TYPE(ty), r}, Kl};
 			else
 				*curi = (Ins){Oparc, r, {TYPE(ty)}, Kl};
+		else if (env)
+			if (arg)
+				*curi = (Ins){Oarge, R, {r}, k};
+			else
+				*curi = (Ins){Opare, r, {R}, k};
 		else
 			if (arg)
 				*curi = (Ins){Oarg, R, {r}, k};
 			else
 				*curi = (Ins){Opar, r, {R}, k};
 		curi++;
+		hasenv |= env;
 		if (peek() == Trparen)
 			break;
 		expect(Tcomma);
diff --git a/sysv.c b/sysv.c
index 1a036a3..c0480f0 100644
--- a/sysv.c
+++ b/sysv.c
@@ -171,7 +171,7 @@ selret(Blk *b, Fn *fn)
 }
 
 static int
-argsclass(Ins *i0, Ins *i1, AClass *ac, int op, AClass *aret)
+argsclass(Ins *i0, Ins *i1, AClass *ac, int op, AClass *aret, Ref *env)
 {
 	int nint, ni, nsse, ns, n, *pn;
 	AClass *a;
@@ -182,8 +182,9 @@ argsclass(Ins *i0, Ins *i1, AClass *ac, int op, AClass *aret)
 	else
 		nint = 6;
 	nsse = 8;
-	for (i=i0, a=ac; i<i1; i++, a++) {
-		if (i->op == op) {
+	for (i=i0, a=ac; i<i1; i++, a++)
+		switch (i->op - op + Oarg) {
+		case Oarg:
 			if (KBASE(i->cls) == 0)
 				pn = &nint;
 			else
@@ -196,7 +197,8 @@ argsclass(Ins *i0, Ins *i1, AClass *ac, int op, AClass *aret)
 			a->align = 3;
 			a->size = 8;
 			a->cls[0] = i->cls;
-		} else {
+			break;
+		case Oargc:
 			n = i->arg[0].val;
 			typclass(a, &typ[n]);
 			if (a->inmem)
@@ -212,8 +214,14 @@ argsclass(Ins *i0, Ins *i1, AClass *ac, int op, AClass *aret)
 				nsse -= ns;
 			} else
 				a->inmem = 1;
+			break;
+		case Oarge:
+			if (op == Opar)
+				*env = i->to;
+			else
+				*env = i->arg[0];
+			break;
 		}
-	}
 
 	return ((6-nint) << 4) | ((8-nsse) << 8);
 }
@@ -236,7 +244,7 @@ MAKESURE(rclob_has_correct_size, sizeof rclob == NRClob * sizeof(int));
  *          |    |    |  ` sse regs returned   (0..2)
  *          |    |    ` gp regs passed         (0..6)
  *          |    ` sse regs passed             (0..8)
- *          ` 1 if calling a vararg function   (0..1)
+ *          ` 1 if rax used to pass data       (0..1)
  */
 
 bits
@@ -268,22 +276,22 @@ bits
 argregs(Ref r, int p[2])
 {
 	bits b;
-	int j, ni, nf, va;
+	int j, ni, nf, ra;
 
 	assert(rtype(r) == RCall);
 	b = 0;
 	ni = (r.val >> 4) & 15;
 	nf = (r.val >> 8) & 15;
-	va = (r.val >> 12) & 1;
+	ra = (r.val >> 12) & 1;
 	for (j=0; j<ni; j++)
 		b |= BIT(rsave[j]);
 	for (j=0; j<nf; j++)
 		b |= BIT(XMM0+j);
 	if (p) {
-		p[0] = ni + va;
+		p[0] = ni + ra;
 		p[1] = nf;
 	}
-	return b | (va ? BIT(RAX) : 0);
+	return b | (ra ? BIT(RAX) : 0);
 }
 
 static Ref
@@ -300,18 +308,20 @@ selcall(Fn *fn, Ins *i0, Ins *i1, RAlloc **rap)
 {
 	Ins *i;
 	AClass *ac, *a, aret;
-	int ca, ni, ns, al, va;
+	int ca, ni, ns, al, varc, envc;
 	uint stk, off;
-	Ref r, r1, r2, reg[2];
+	Ref r, r1, r2, reg[2], env;
 	RAlloc *ra;
 
+	env = R;
 	ac = alloc((i1-i0) * sizeof ac[0]);
+
 	if (!req(i1->arg[1], R)) {
 		assert(rtype(i1->arg[1]) == RType);
 		typclass(&aret, &typ[i1->arg[1].val]);
-		ca = argsclass(i0, i1, ac, Oarg, &aret);
+		ca = argsclass(i0, i1, ac, Oarg, &aret, &env);
 	} else
-		ca = argsclass(i0, i1, ac, Oarg, 0);
+		ca = argsclass(i0, i1, ac, Oarg, 0, &env);
 
 	for (stk=0, a=&ac[i1-i0]; a>ac;)
 		if ((--a)->inmem) {
@@ -366,10 +376,15 @@ selcall(Fn *fn, Ins *i0, Ins *i1, RAlloc **rap)
 			ca += 1 << 2;
 		}
 	}
-	va = i1->op == Ovacall;
-	ca |= va << 12;
+	envc = !req(R, env);
+	varc = i1->op == Ovacall;
+	if (varc && envc)
+		err("sysv abi does not support variadic env calls");
+	ca |= (varc | envc) << 12;
 	emit(Ocall, i1->cls, R, i1->arg[0], CALL(ca));
-	if (va)
+	if (envc)
+		emit(Ocopy, Kl, TMP(RAX), env, R);
+	if (varc)
 		emit(Ocopy, Kw, TMP(RAX), getcon((ca >> 8) & 15, fn), R);
 
 	ni = ns = 0;
@@ -418,17 +433,18 @@ selpar(Fn *fn, Ins *i0, Ins *i1)
 	AClass *ac, *a, aret;
 	Ins *i;
 	int ni, ns, s, al, fa;
-	Ref r;
+	Ref r, env;
 
+	env = R;
 	ac = alloc((i1-i0) * sizeof ac[0]);
 	curi = &insb[NIns];
 	ni = ns = 0;
 
 	if (fn->retty >= 0) {
 		typclass(&aret, &typ[fn->retty]);
-		fa = argsclass(i0, i1, ac, Opar, &aret);
+		fa = argsclass(i0, i1, ac, Opar, &aret, &env);
 	} else
-		fa = argsclass(i0, i1, ac, Opar, 0);
+		fa = argsclass(i0, i1, ac, Opar, 0, &env);
 
 	for (i=i0, a=ac; i<i1; i++, a++) {
 		if (i->op != Oparc || a->inmem)
@@ -478,6 +494,9 @@ selpar(Fn *fn, Ins *i0, Ins *i1)
 			emit(Ocopy, i->cls, i->to, r, R);
 	}
 
+	if (!req(R, env))
+		emit(Ocopy, Kl, env, TMP(RAX), R);
+
 	return fa | (s*4)<<12;
 }
 
@@ -641,8 +660,8 @@ abi(Fn *fn)
 		b->visit = 0;
 
 	/* lower parameters */
-	for (b=fn->start, i=b->ins; i-b->ins < b->nins; i++)
-		if (i->op != Opar && i->op != Oparc)
+	for (b=fn->start, i=b->ins; i-b->ins<b->nins; i++)
+		if (!ispar(i->op))
 			break;
 	fa = selpar(fn, b->ins, i);
 	n = b->nins - (i - b->ins) + (&insb[NIns] - curi);
@@ -670,8 +689,7 @@ abi(Fn *fn)
 			case Ocall:
 			case Ovacall:
 				for (i0=i; i0>b->ins; i0--)
-					if ((i0-1)->op != Oarg)
-					if ((i0-1)->op != Oargc)
+					if (!isarg((i0-1)->op))
 						break;
 				selcall(fn, i0, i, &ral);
 				i = i0;
diff --git a/tools/lexh.c b/tools/lexh.c
index db27f8f..9e8016a 100644
--- a/tools/lexh.c
+++ b/tools/lexh.c
@@ -22,7 +22,7 @@ char *tok[] = {
 	"ceql", "cnel", "cles", "clts", "cgts", "cges",
 	"cnes", "ceqs", "cos", "cuos", "cled", "cltd",
 	"cgtd", "cged", "cned", "ceqd", "cod", "cuod",
-	"vaarg", "vastart", "...",
+	"vaarg", "vastart", "...", "env",
 
 	"call", "phi", "jmp", "jnz", "ret", "export",
 	"function", "type", "data", "align", "l", "w",