diff options
-rw-r--r-- | all.h | 4 | ||||
-rw-r--r-- | parse.c | 24 | ||||
-rw-r--r-- | sysv.c | 66 | ||||
-rw-r--r-- | tools/lexh.c | 2 |
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", |