summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--6/gengas.c2
-rw-r--r--6/genp9.c2
-rw-r--r--6/simp.c10
-rw-r--r--6q/Makefile12
-rw-r--r--6q/blob.c390
-rw-r--r--6q/gen.c1954
-rw-r--r--6q/main.c303
-rw-r--r--6q/qasm.h141
-rw-r--r--6q/qbe.def110
-rw-r--r--6q/typeinfo.c432
-rw-r--r--Makefile2
-rwxr-xr-xboot6qm.sh136
-rw-r--r--lib/std/bytealloc.myr8
-rw-r--r--mi/flatten.c27
-rw-r--r--mi/mi.h2
-rw-r--r--mk/c.mk17
-rw-r--r--parse/node.c2
-rw-r--r--parse/ops.def22
-rw-r--r--parse/parse.h3
-rw-r--r--parse/specialize.c2
-rw-r--r--parse/type.c34
-rw-r--r--parse/types.def2
-rw-r--r--util/pack.c18
-rw-r--r--util/util.h1
24 files changed, 3572 insertions, 60 deletions
diff --git a/6/gengas.c b/6/gengas.c
index d37f37e..45e35b0 100644
--- a/6/gengas.c
+++ b/6/gengas.c
@@ -450,7 +450,7 @@ gengas(Node *file, FILE *fd)
case Nimpl:
break;
case Ndecl:
- n = flattenfn(n);
+ n = flattenfn(n, NULL, NULL);
simpglobl(n, globls, &fn, &nfn, &blob, &nblob);
break;
default:
diff --git a/6/genp9.c b/6/genp9.c
index 4a19891..4a40099 100644
--- a/6/genp9.c
+++ b/6/genp9.c
@@ -463,7 +463,7 @@ genp9(Node *file, FILE *fd)
case Nimpl:
break;
case Ndecl:
- n = flattenfn(n);
+ n = flattenfn(n, NULL, NULL);
simpglobl(n, globls, &fn, &nfn, &blob, &nblob);
break;
default:
diff --git a/6/simp.c b/6/simp.c
index c72f347..2b03ec4 100644
--- a/6/simp.c
+++ b/6/simp.c
@@ -844,17 +844,11 @@ simpucon(Simp *s, Node *n, Node *dst)
Node *r;
Type *ty;
Ucon *uc;
- size_t i, o;
+ size_t o;
/* find the ucon we're constructing here */
ty = tybase(n->expr.type);
- uc = NULL;
- for (i = 0; i < ty->nmemb; i++) {
- if (!strcmp(namestr(n->expr.args[0]), namestr(ty->udecls[i]->name))) {
- uc = ty->udecls[i];
- break;
- }
- }
+ uc = finducon(ty, n->expr.args[0]);
if (!uc)
die("Couldn't find union constructor");
diff --git a/6q/Makefile b/6q/Makefile
new file mode 100644
index 0000000..86deb6b
--- /dev/null
+++ b/6q/Makefile
@@ -0,0 +1,12 @@
+INSTBIN=6qm
+OBJ= \
+ blob.o \
+ gen.o \
+ main.o \
+ typeinfo.o \
+
+
+DEPS=../parse/libparse.a ../mi/libmi.a ../util/libutil.a
+
+include ../config.mk
+include ../mk/c.mk
diff --git a/6q/blob.c b/6q/blob.c
new file mode 100644
index 0000000..f582fe4
--- /dev/null
+++ b/6q/blob.c
@@ -0,0 +1,390 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "parse.h"
+#include "mi.h"
+#include "qasm.h"
+#include "../config.h"
+
+
+Blob *
+mkblobi(Blobtype type, uint64_t ival)
+{
+ Blob *b;
+
+ b = zalloc(sizeof(Blob));
+ b->type = type;
+ b->ival = ival;
+ return b;
+}
+
+Blob *
+mkblobpad(size_t sz)
+{
+ Blob *b;
+
+ b = zalloc(sizeof(Blob));
+ b->type = Btpad;
+ b->npad = sz;
+ return b;
+}
+
+Blob *
+mkblobbytes(char *buf, size_t len)
+{
+ Blob *b;
+
+ b = zalloc(sizeof(Blob));
+ b->type = Btbytes;
+ b->bytes.buf = buf;
+ b->bytes.len = len;
+ return b;
+}
+
+Blob *
+mkblobseq(Blob **sub, size_t nsub)
+{
+ Blob *b;
+
+ b = zalloc(sizeof(Blob));
+ b->type = Btseq;
+ b->seq.sub = sub;
+ b->seq.nsub = nsub;
+ return b;
+}
+
+Blob *
+mkblobref(char *lbl, size_t off, int isextern)
+{
+ Blob *b;
+
+ b = zalloc(sizeof(Blob));
+ b->type = Btref;
+ b->ref.str = strdup(lbl);
+ b->ref.isextern = isextern;
+ b->ref.off = off;
+ return b;
+}
+
+void
+blobfree(Blob *b)
+{
+ size_t i;
+
+ if (!b)
+ return;
+ switch (b->type) {
+ case Btref:
+ free(b->lbl);
+ break;
+ case Btseq:
+ for (i = 0; i < b->seq.nsub; i++)
+
+ blobfree(b->seq.sub[i]);
+ break;
+ default:
+ break;
+ }
+ free(b);
+}
+
+static size_t
+getintlit(Node *n, char *failmsg)
+{
+ if (exprop(n) != Olit)
+ fatal(n, "%s", failmsg);
+ n = n->expr.args[0];
+ if (n->lit.littype != Lint)
+ fatal(n, "%s", failmsg);
+ return n->lit.intval;
+}
+
+static void
+b(Blob *b, Blob *n)
+{
+ lappend(&b->seq.sub, &b->seq.nsub, n);
+}
+
+static size_t
+blobpad(Blob *seq, size_t sz)
+{
+ if (sz)
+ b(seq, mkblobpad(sz));
+ return sz;
+}
+
+static size_t
+bloblit(Gen *g, Blob *seq, Node *n, Type *ty)
+{
+ Blobtype intsz[] = {
+ [1] = Bti8,
+ [2] = Bti16,
+ [4] = Bti32,
+ [8] = Bti64
+ };
+ union {
+ float fv;
+ double dv;
+ uint64_t qv;
+ uint32_t lv;
+ } u;
+ char buf[128];
+ char *lbl;
+ size_t sz;
+ Node *v;
+
+ assert(exprop(n) == Olit);
+ v = n->expr.args[0];
+ sz = tysize(ty);
+ switch (v->lit.littype) {
+ case Lvoid: break;
+ case Lint: b(seq, mkblobi(intsz[sz], v->lit.intval)); break;
+ case Lbool: b(seq, mkblobi(Bti8, v->lit.boolval)); break;
+ case Lchr: b(seq, mkblobi(Bti32, v->lit.chrval)); break;
+ case Lflt:
+ if (tybase(v->lit.type)->type == Tyflt32) {
+ u.fv = v->lit.fltval;
+ b(seq, mkblobi(Bti32, u.lv));
+ } else if (tybase(v->lit.type)->type == Tyflt64) {
+ u.dv = v->lit.fltval;
+ b(seq, mkblobi(Bti64, u.qv));
+ }
+ break;
+ case Lstr:
+ /*
+ FIXME: dedup strings.
+ if (hthas(strtab, &v->lit.strval)) {
+ lbl = htget(strtab, &v->lit.strval);
+ } else {
+ lbl = genlocallblstr(buf, sizeof buf);
+ htput(strtab, &v->lit.strval, strdup(lbl));
+ }
+ */
+ lbl = genlblstr(buf, sizeof buf, "");
+ if (v->lit.strval.len > 0)
+ b(seq, mkblobref(lbl, 0, 1));
+ else
+ b(seq, mkblobi(Bti64, 0));
+ b(seq, mkblobi(Bti64, v->lit.strval.len));
+ break;
+ case Lfunc:
+ fatal(n, "Generating this shit ain't ready yet");
+ break;
+ case Llbl:
+ die("Can't generate literal labels, ffs. They're not data.");
+ break;
+ }
+ return sz;
+}
+
+static size_t
+blobslice(Gen *g, Blob *seq, Node *n)
+{
+ Node *base, *lo, *hi;
+ ssize_t loval, hival, sz;
+ Blob *slbase;
+ char *lbl;
+
+ base = n->expr.args[0];
+ lo = n->expr.args[1];
+ hi = n->expr.args[2];
+
+ /* by this point, all slicing operations should have had their bases
+ * pulled out, and we should have vars with their pseudo-decls in their
+ * place */
+ loval = getintlit(lo, "lower bound in slice is not constant literal");
+ hival = getintlit(hi, "upper bound in slice is not constant literal");
+ if (exprop(base) == Ovar && base->expr.isconst) {
+ sz = tysize(tybase(exprtype(base))->sub[0]);
+ lbl = htget(g->globls, base);
+ slbase = mkblobref(lbl, loval*sz, 1);
+ } else if (exprop(base) == Olit) {
+ slbase = mkblobi(Bti64, getintlit(base, "invalid base expr"));
+ } else {
+ fatal(base, "slice base is not a constant value");
+ }
+
+ b(seq, slbase);
+ b(seq, mkblobi(Bti64, (hival - loval)));
+ return 16;
+}
+
+static Node *
+structmemb(Node *n, char *dcl)
+{
+ size_t i;
+
+ for (i = 0; i < n->expr.nargs; i++)
+ if (!strcmp(namestr(n->expr.args[i]->expr.idx), dcl))
+ return n->expr.args[i];
+ return NULL;
+}
+
+static size_t
+blobstruct(Gen *g, Blob *seq, Node *n)
+{
+ size_t i, sz, pad, end, ndcl;
+ Node **dcl, *m;
+ Type *t;
+
+ sz = 0;
+ t = tybase(exprtype(n));
+ assert(t->type == Tystruct);
+ dcl = t->sdecls;
+ ndcl = t->nmemb;
+
+ for (i = 0; i < ndcl; i++) {
+ pad = alignto(sz, decltype(dcl[i]));
+ m = structmemb(n, declname(dcl[i]));
+ sz += blobpad(seq, pad - sz);
+ if (m)
+ sz += blobrec(g, seq, m);
+ else
+ sz += blobpad(seq, size(dcl[i]));
+ }
+ end = alignto(sz, t);
+ sz += blobpad(seq, end - sz);
+ return sz;
+}
+
+static size_t
+blobucon(Gen *g, Blob *seq, Node *n)
+{
+ size_t sz, pad;
+ Ucon *uc;
+
+ sz = 4;
+ uc = finducon(exprtype(n), n->expr.args[0]);
+ b(seq, mkblobi(Bti32, uc->id));
+ if (n->expr.nargs > 1) {
+ pad = tyalign(exprtype(n->expr.args[1])) - sz;
+ sz += blobpad(seq, pad);
+ sz += blobrec(g, seq, n->expr.args[1]);
+ }
+ sz += blobpad(seq, size(n) - sz);
+ return sz;
+}
+
+size_t
+blobrec(Gen *g, Blob *b, Node *n)
+{
+ size_t i, sz, end;
+ Type *ty;
+
+ ty = exprtype(n);
+ switch(exprop(n)) {
+ case Oucon: sz = blobucon(g, b, n); break;
+ case Oslice: sz = blobslice(g, b, n); break;
+ case Ostruct: sz = blobstruct(g, b, n); break;
+ case Olit: sz = bloblit(g, b, n, ty); break;
+ case Otup:
+ case Oarr:
+ /* Assumption: We sorted this while folding */
+ sz = 0;
+ if (!n->expr.args)
+ break;
+ for (i = 0; i < n->expr.nargs; i++) {
+ end = alignto(sz, exprtype(n->expr.args[i]));
+ sz += blobpad(b, end - sz);
+ sz += blobrec(g, b, n->expr.args[i]);
+ }
+ /* if we need padding at the end.. */
+ end = alignto(sz, exprtype(n));
+ sz += blobpad(b, end - sz);
+ break;
+ default:
+ dump(n, stdout);
+ die("Nonliteral initializer for global");
+ break;
+ }
+ return sz;
+}
+
+
+static void
+encodemin(Gen *g, uint64_t val)
+{
+ size_t i, shift;
+ uint8_t b;
+
+ if (val < 128) {
+ fprintf(g->f, "\tb %lld,\n", (long long)val);
+ return;
+ }
+
+ for (i = 1; i < 8; i++)
+ if (val < 1ULL << (7*i))
+ break;
+ shift = 8 - i;
+ b = ~0ull << (shift + 1);
+ b |= val & ~(~0ull << shift);
+ fprintf(g->f, "\tb %u,\n", b);
+ val >>= shift;
+ while (val != 0) {
+ fprintf(g->f, "\tb %u,\n", (uint)val & 0xff);
+ val >>= 8;
+ }
+}
+
+static void
+outbytes(Gen *g, char *p, size_t sz)
+{
+ size_t i;
+
+ for (i = 0; i < sz; i++) {
+ if (i % 60 == 0)
+ fprintf(g->f, "\tb \"");
+ if (p[i] == '"' || p[i] == '\\')
+ fprintf(g->f, "\\");
+ if (isprint(p[i]))
+ fprintf(g->f, "%c", p[i]);
+ else
+ fprintf(g->f, "\\%03o", (uint8_t)p[i] & 0xff);
+ /* line wrapping for readability */
+ if (i % 60 == 59 || i == sz - 1)
+ fprintf(g->f, "\",\n");
+ }
+}
+
+void
+genblob(Gen *g, Blob *b)
+{
+ size_t i;
+
+ if (b->lbl) {
+ if (b->iscomdat)
+ /* FIXME: emit once */
+ if (b->isglobl)
+ fprintf(g->f, "export ");
+ fprintf(g->f, "data $%s = {\n", b->lbl);
+ }
+
+ switch (b->type) {
+ case Btimin: encodemin(g, b->ival); break;
+ case Bti8: fprintf(g->f, "\tb %lld,\n", (long long)b->ival); break;
+ case Bti16: fprintf(g->f, "\th %lld,\n", (long long)b->ival); break;
+ case Bti32: fprintf(g->f, "\tw %lld,\n", (long long)b->ival); break;
+ case Bti64: fprintf(g->f, "\tl %lld,\n", (long long)b->ival); break;
+ case Btbytes: outbytes(g, b->bytes.buf, b->bytes.len); break;
+ case Btpad: fprintf(g->f, "\tz %lld,\n", (long long)b->npad); break;
+ case Btref: fprintf(g->f, "\tl $%s + %lld,\n", b->ref.str, (long long)b->ref.off); break;
+ case Btseq:
+ for (i = 0; i < b->seq.nsub; i++)
+ genblob(g, b->seq.sub[i]);
+ break;
+ }
+ if(b->lbl) {
+ fprintf(g->f, "}\n\n");
+ }
+}
+
diff --git a/6q/gen.c b/6q/gen.c
new file mode 100644
index 0000000..250a179
--- /dev/null
+++ b/6q/gen.c
@@ -0,0 +1,1954 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "parse.h"
+#include "mi.h"
+#include "qasm.h"
+#include "../config.h"
+
+char
+qtag(Gen *g, Type *ty);
+static void
+outtypebody(Gen *g, Type *ty);
+static void
+outqtype(Gen *g, Type *ty);
+
+static void
+out(Gen *g, Qop o, Loc r, Loc a, Loc b);
+static void
+ocall(Gen *g, Loc fn, Loc ret, Loc env, Loc *args, Type **types, size_t nargs);
+static Loc
+rval(Gen *g, Node *n);
+static Loc
+lval(Gen *g, Node *n);
+static Loc
+seqbase(Gen *g, Node *sl, Node *off);
+static Loc
+slicelen(Gen *g, Node *n, Type *rty);
+static Loc
+gencast(Gen *g, Srcloc loc, Loc val, Type *to, Type *from);
+
+static Loc
+abortoob;
+static Loc
+ptrsize;
+
+static int
+isexport(Node *dcl)
+{
+ Node *n;
+
+ /* Vishidden should also be exported. */
+ if (dcl->decl.vis != Visintern)
+ return 1;
+ n = dcl->decl.name;
+ if (!n->name.ns && streq(n->name.name, "main"))
+ return 1;
+ if (streq(n->name.name, "__init__"))
+ return 1;
+ return 0;
+}
+
+int
+isstack(Node *n)
+{
+ if (n->type == Nexpr)
+ return isstacktype(n->expr.type);
+ else
+ return isstacktype(n->decl.type);
+}
+
+char *
+asmname(Node *n, char sigil)
+{
+ char *ns, *name, *sep;
+
+ ns = n->name.ns;
+ if (!ns)
+ ns = "";
+ name = n->name.name;
+ sep = "";
+ if (ns && ns[0])
+ sep = "$";
+ return strfmt("%c%s%s%s", sigil, ns, sep, name);
+}
+
+
+static Loc
+qtemp(Gen *g, char type)
+{
+ return (Loc){.kind=Ltemp, .tmp=g->nexttmp++, .tag=type};
+}
+
+static Loc
+temp(Gen *g, Node *n)
+{
+ char type;
+
+ if (n->type == Ndecl)
+ type = qtag(g, decltype(n));
+ else
+ type = qtag(g, exprtype(n));
+ return (Loc){.kind=Ltemp, .tmp=g->nexttmp++, .tag=type};
+}
+
+static Loc
+qvar(Gen *g, Node *n)
+{
+ char tag;
+
+ assert(n);
+ if (n->type == Nexpr && exprop(n) == Ovar)
+ n = decls[n->expr.did];
+ assert(n->type == Ndecl);
+ tag = qtag(g, n->decl.type);
+ return (Loc){.kind=Ldecl, .dcl=n->decl.did, .tag=tag};
+}
+
+static Loc
+qlabelstr(Gen *g, char *lbl)
+{
+ return (Loc){.kind=Llabel, .lbl=lbl, .tag='l'};
+}
+
+static Loc
+qlabel(Gen *g, Node *lbl)
+{
+ return (Loc){.kind=Llabel, .lbl=lblstr(lbl), .tag='l'};
+}
+
+static Loc
+qconst(Gen *g, uint64_t cst, char tag)
+{
+ return (Loc){.kind=Lconst, .cst=cst, .tag=tag};
+}
+
+static Loc
+qblob(Gen *g, Blob *b)
+{
+ return (Loc){.kind=Lblob, .blob=b, .tag='l'};
+}
+
+static void
+out(Gen *g, Qop op, Loc r, Loc a, Loc b)
+{
+ if (g->ninsn == g->insnsz) {
+ g->insnsz += g->insnsz/2 + 1;
+ g->insn = xrealloc(g->insn, g->insnsz * sizeof(Insn));
+ }
+ g->insn[g->ninsn].op = op;
+ g->insn[g->ninsn].ret = r;
+ g->insn[g->ninsn].arg[0] = a;
+ g->insn[g->ninsn].arg[1] = b;
+ g->ninsn++;
+}
+
+static void
+ocall(Gen *g, Loc fn, Loc ret, Loc env, Loc *args, Type **types, size_t nargs)
+{
+ if (g->ninsn == g->insnsz) {
+ g->insnsz += g->insnsz/2 + 1;
+ g->insn = xrealloc(g->insn, g->insnsz * sizeof(Insn));
+ }
+ g->insn[g->ninsn].op = Qcall;
+ g->insn[g->ninsn].fn = fn;
+ g->insn[g->ninsn].ret = ret;
+ g->insn[g->ninsn].env = env;
+ g->insn[g->ninsn].farg = args;
+ g->insn[g->ninsn].fty = types;
+ g->insn[g->ninsn].nfarg = nargs;
+ g->ninsn++;
+}
+
+Type *
+codetype(Type *ft)
+{
+ ft = tybase(ft);
+ if (ft->type == Tycode)
+ return ft;
+ assert(ft->type == Tyfunc);
+ ft = tydup(ft);
+ ft->type = Tycode;
+ return ft;
+}
+
+static void
+addlocal(Gen *g, Node *n)
+{
+ lappend(&g->local, &g->nlocal, n);
+}
+
+static Loc
+qstacktemp(Gen *g, Node *e)
+{
+ Node *dcl;
+
+ if (e->type == Nexpr)
+ gentemp(e->loc, e->expr.type, &dcl);
+ else if (e->type == Nfunc)
+ gentemp(e->loc, e->func.type, &dcl);
+ else
+ dcl = e;
+ addlocal(g, dcl);
+ return qvar(g, dcl);
+}
+
+static Loc
+ptrsized(Gen *g, Loc v)
+{
+ Loc r;
+
+ if (v.tag == 'l')
+ return v;
+ r = qtemp(g, 'l');
+ switch (v.tag) {
+ case 'w': out(g, Qextuw, r, v, Zq); break;
+ case 'h': out(g, Qextuh, r, v, Zq); break;
+ case 'b': out(g, Qextub, r, v, Zq); break;
+ default: die("invalid tag\n"); break;
+ }
+ return r;
+}
+
+char
+qtag(Gen *g, Type *ty)
+{
+ switch (ty->type) {
+ case Tybool: return 'w'; break;
+ case Tychar: return 'w'; break;
+ case Tyint8: return 'w'; break;
+ case Tyint16: return 'w'; break;
+ case Tyint: return 'w'; break;
+ case Tyint32: return 'w'; break;
+ case Tyint64: return 'l'; break;
+ case Tybyte: return 'w'; break;
+ case Tyuint8: return 'w'; break;
+ case Tyuint16: return 'w'; break;
+ case Tyuint: return 'w'; break;
+ case Tyuint32: return 'w'; break;
+ case Tyuint64: return 'l'; break;
+ case Tyflt32: return 's'; break;
+ case Tyflt64: return 'd'; break;
+ case Typtr: return 'l'; break;
+ default: return 'l'; break;
+ }
+}
+
+char *
+qtype(Gen *g, Type *ty)
+{
+ ty = tydedup(ty);
+ switch (ty->type) {
+ case Tybool: return "b"; break;
+ case Tychar: return "w"; break;
+ case Tyint8: return "b"; break;
+ case Tyint16: return "h"; break;
+ case Tyint: return "w"; break;
+ case Tyint32: return "w"; break;
+ case Tyint64: return "l"; break;
+ case Tybyte: return "b"; break;
+ case Tyuint8: return "b"; break;
+ case Tyuint16: return "h"; break;
+ case Tyuint: return "w"; break;
+ case Tyuint32: return "w"; break;
+ case Tyuint64: return "l"; break;
+ case Tyflt32: return "s"; break;
+ case Tyflt64: return "d"; break;
+ case Typtr: return "l"; break;
+ default: return g->typenames[ty->tid]; break;
+ }
+}
+
+static Qop
+loadop(Type *ty)
+{
+ Qop op;
+
+ switch (tybase(ty)->type) {
+ case Tybool: op = Qloadub; break;
+ case Tybyte: op = Qloadub; break;
+ case Tyuint8: op = Qloadub; break;
+ case Tyint8: op = Qloadsb; break;
+
+ case Tyint16: op = Qloadsh; break;
+ case Tyuint16: op = Qloaduh; break;
+
+ case Tychar: op = Qloaduw; break;
+ case Tyint: op = Qloadsw; break;
+ case Tyuint: op = Qloadsw; break;
+ case Tyint32: op = Qloadsw; break;
+ case Tyuint32: op = Qloaduw; break;
+
+ case Tyint64: op = Qloadl; break;
+ case Tyuint64: op = Qloadl; break;
+ case Typtr: op = Qloadl; break;
+ case Tycode: op = Qloadl; break;
+
+ case Tyflt32: op = Qloads; break;
+ case Tyflt64: op = Qloadd; break;
+ default: die("badload"); break;
+ }
+ return op;
+}
+
+static Qop
+storeop(Type *ty)
+{
+ Qop op;
+
+ switch (tybase(ty)->type) {
+ case Tybool: op = Qstoreb; break;
+ case Tybyte: op = Qstoreb; break;
+ case Tyuint8: op = Qstoreb; break;
+ case Tyint8: op = Qstoreb; break;
+
+ case Tyint16: op = Qstoreh; break;
+ case Tyuint16: op = Qstoreh; break;
+
+ case Tychar: op = Qstorew; break;
+ case Tyint: op = Qstorew; break;
+ case Tyuint: op = Qstorew; break;
+ case Tyint32: op = Qstorew; break;
+ case Tyuint32: op = Qstorew; break;
+
+ case Tyint64: op = Qstorel; break;
+ case Tyuint64: op = Qstorel; break;
+ case Typtr: op = Qstorel; break;
+
+ case Tyflt32: op = Qstores; break;
+ case Tyflt64: op = Qstored; break;
+ default: die("badstore"); break;
+ }
+ return op;
+}
+
+void
+fillglobls(Stab *st, Htab *globls)
+{
+ size_t i, j, nk, nns;
+ void **k, **ns;
+ Stab *stab;
+ Node *s;
+ char *n;
+
+ k = htkeys(st->dcl, &nk);
+ for (i = 0; i < nk; i++) {
+ s = htget(st->dcl, k[i]);
+ if (isconstfn(s))
+ s->decl.type = codetype(s->decl.type);
+ n = asmname(s->decl.name, '$');
+ htput(globls, s, n);
+ }
+ free(k);
+
+ ns = htkeys(file->file.ns, &nns);
+ for (j = 0; j < nns; j++) {
+ stab = htget(file->file.ns, ns[j]);
+ k = htkeys(stab->dcl, &nk);
+ for (i = 0; i < nk; i++) {
+ s = htget(stab->dcl, k[i]);
+ n = asmname(s->decl.name, '$');
+ htput(globls, s, n);
+ }
+ free(k);
+ }
+ free(ns);
+}
+
+static void
+initconsts(Gen *g, Htab *globls)
+{
+ Type *ty;
+ Node *name;
+ Node *dcl;
+ char *n;
+
+ ptrsize = qconst(g, Ptrsz, 'l');
+ ty = mktyfunc(Zloc, NULL, 0, mktype(Zloc, Tyvoid));
+ ty->type = Tycode;
+ name = mknsname(Zloc, "_rt", "abort_oob");
+ dcl = mkdecl(Zloc, name, ty);
+ dcl->decl.isconst = 1;
+ dcl->decl.isextern = 1;
+ dcl->decl.isglobl = 1;
+ n = asmname(dcl->decl.name, '$');
+ htput(globls, dcl, n);
+
+ abortoob = qvar(g, dcl);
+}
+
+static Loc
+binop(Gen *g, Qop op, Node *a, Node *b)
+{
+ Loc t, l, r;
+ char tag;
+
+ tag = qtag(g, exprtype(a));
+ t = qtemp(g, tag);
+ l = rval(g, a);
+ r = rval(g, b);
+ out(g, op, t, l, r);
+ return t;
+}
+
+static Loc
+binopk(Gen *g, Qop op, Node *n, uvlong k)
+{
+ Loc t, l, r;
+ char tag;
+
+ tag = qtag(g, exprtype(n));
+ t = qtemp(g, tag);
+ l = rval(g, n);
+ r = qconst(g, k, l.tag);
+ out(g, op, t, l, r);
+ return t;
+}
+
+/*static*/ Loc getcode(Gen *g, Node *n)
+{
+ Loc r, p;
+
+ if (isconstfn(n))
+ r = qvar(g, n);
+ else {
+ r = qtemp(g, 'l');
+ p = binopk(g, Qadd, n, Ptrsz);
+ out(g, Qloadl, r, p, Zq);
+ }
+ return r;
+}
+
+static Loc
+slicelen(Gen *g, Node *n, Type *ty)
+{
+ Loc sl, lp, r;
+
+ ty = tybase(ty);
+ sl = rval(g, n);
+ lp = qtemp(g, 'l');
+ r = qtemp(g, qtag(g, ty));
+ out(g, Qadd, lp, sl, ptrsize);
+ out(g, loadop(ty), r, lp, Zq);
+ return r;
+}
+
+Loc
+cmpop(Gen *g, Op op, Node *ln, Node *rn)
+{
+ Qop intcmptab[][2] = {
+ /* signed */
+ [Ole] = {Qcslew, Qcslel},
+ [Olt] = {Qcsltw, Qcsltl},
+ [Ogt] = {Qcsgtw, Qcsgtl},
+ [Oge] = {Qcsgew, Qcsgel},
+ [Oeq] = {Qceqw, Qceql},
+ [One] = {Qcnew, Qcnel},
+ /* unsigned */
+ [Oule] = {Qculew, Qculel},
+ [Oult] = {Qcultw, Qcultl},
+ [Ougt] = {Qcugtw, Qcugtl},
+ [Ouge] = {Qcugew, Qcugel},
+ [Oueq] = {Qceqw, Qceql},
+ [Oune] = {Qcnew, Qcnel},
+ };
+
+ Qop fltcmptab[][2] = {
+ [Ofle] = {Qcles, Qcled},
+ [Oflt] = {Qclts, Qcltd},
+ [Ofgt] = {Qcgts, Qcgtd},
+ [Ofge] = {Qcges, Qcged},
+ [Ofeq] = {Qceqs, Qceqd},
+ [Ofne] = {Qcnes, Qcned},
+ };
+
+ Loc l, r, t;
+ Type *ty;
+ Qop qop;
+
+ ty = exprtype(ln);
+ l = rval(g, ln);
+ r = rval(g, rn);
+ t = qtemp(g, qtag(g, ty));
+ if (istyfloat(ty))
+ qop = fltcmptab[op][l.tag == 'd'];
+ else
+ qop = intcmptab[op][l.tag == 'l'];
+
+ out(g, qop, t, l, r);
+ return t;
+}
+
+static Loc
+intcvt(Gen *g, Loc v, char to, int sz, int sign)
+{
+ Loc t;
+ Qop op;
+
+ static const Qop optab[][2] = {
+ [8] = {Qcopy, Qcopy},
+ [4] = {Qextuw, Qextsw},
+ [2] = {Qextuh, Qextsh},
+ [1] = {Qextub, Qextsb},
+ };
+
+ t = qtemp(g, to);
+ if (sz == 4 && to == 'w')
+ op = Qcopy;
+ else
+ op = optab[sz][sign];
+ out(g, op, t, v, Zq);
+ return t;
+}
+
+static Loc
+gencast(Gen *g, Srcloc loc, Loc val, Type *to, Type *from)
+{
+ Loc a, r;
+
+ r = val;
+ /* do the type conversion */
+ switch (tybase(to)->type) {
+ case Tybool:
+ case Tyint8: case Tyint16: case Tyint32: case Tyint64:
+ case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
+ case Tyint: case Tyuint: case Tychar: case Tybyte:
+ case Typtr:
+ switch (tybase(from)->type) {
+ /* ptr -> slice conversion is disallowed */
+ case Tyslice:
+ /* FIXME: we should only allow casting to pointers. */
+ if (tysize(to) != Ptrsz)
+ lfatal(loc, "bad cast from %s to %s", tystr(from), tystr(to));
+ r = qtemp(g, 'l');
+ out(g, Qloadl, r, val, Zq);
+ break;
+ case Tyfunc:
+ if (to->type != Typtr)
+ lfatal(loc, "bad cast from %s to %s", tystr(from), tystr(to));
+ a = qtemp(g, 'l');
+ r = qtemp(g, 'l');
+ out(g, Qadd, a, val, ptrsize);
+ out(g, Qloadl, r, a, Zq);
+ break;
+ /* signed conversions */
+ case Tyint8: case Tyint16: case Tyint32: case Tyint64:
+ case Tyint:
+ r = intcvt(g, val, qtag(g, to), tysize(from), 1);
+ break;
+ /* unsigned conversions */
+ case Tybool:
+ case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
+ case Tyuint: case Tychar: case Tybyte:
+ case Typtr:
+ r = intcvt(g, val, qtag(g, to), tysize(from), 0);
+ break;
+ case Tyflt32:
+ if (tybase(to)->type == Typtr)
+ lfatal(loc, "bad cast from %s to %s", tystr(from), tystr(to));
+ r = qtemp(g, qtag(g, to));
+ out(g, Qstosi, r, val, Zq);
+ break;
+ case Tyflt64:
+ if (tybase(to)->type == Typtr)
+ lfatal(loc, "bad cast from %s to %s", tystr(from), tystr(to));
+ r = qtemp(g, qtag(g, to));
+ out(g, Qdtosi, r, val, Zq);
+ break;
+ default:
+ lfatal(loc, "bad cast from %s to %s", tystr(from), tystr(to));
+ }
+ break;
+ case Tyflt32: case Tyflt64:
+ switch (from->type) {
+ case Tyint8: case Tyint16: case Tyint32: case Tyint64:
+ case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
+ case Tyint: case Tyuint: case Tychar: case Tybyte:
+ r = qtemp(g, qtag(g, to));
+ out(g, Qswtof, r, val, Zq);
+ break;
+ case Tyflt32: case Tyflt64:
+ fprintf(stderr, "flt<->flt casts not supported");
+ r = qconst(g, 0, qtag(g, to));
+ break;
+ break;
+ default:
+ lfatal(loc, "bad cast from %s to %s", tystr(from), tystr(to));
+ break;
+ }
+ break;
+ /* no other destination types are handled as things stand */
+ default:
+ lfatal(loc, "bad cast from %s to %s", tystr(from), tystr(to));
+ }
+ return r;
+}
+
+static Loc
+simpcast(Gen *g, Node *val, Type *to)
+{
+ Loc l;
+
+ l = rval(g, val);
+ return gencast(g, val->loc, l, to, exprtype(val));
+}
+
+
+void
+blit(Gen *g, Loc dst, Loc src, size_t sz, size_t align)
+{
+ static const Qop ops[][2] = {
+ [8] = {Qloadl, Qstorel},
+ [4] = {Qloaduw, Qstorew},
+ [2] = {Qloaduh, Qstoreh},
+ [1] = {Qloadub, Qstoreb},
+ };
+ Loc l, a, s, d;
+ size_t i;
+
+ assert(sz % align == 0);
+ s = qtemp(g, 'l');
+ d = qtemp(g, 'l');
+ l = qtemp(g, 'l');
+ a = qconst(g, align, 'l');
+ out(g, Qcopy, s, src, Zq);
+ out(g, Qcopy, d, dst, Zq);
+ for (i = 0; i < sz; i += align) {
+ out(g, ops[align][0], l, s, Zq);
+ out(g, ops[align][1], Zq, l, d);
+ out(g, Qadd, s, s, a);
+ out(g, Qadd, d, d, a);
+ }
+}
+
+Loc
+assign(Gen *g, Node *dst, Node* src)
+{
+ Loc d, s;
+ Type *ty;
+
+ ty = exprtype(dst);
+ d = lval(g, dst);
+ s = rval(g, src);
+ if (isstacktype(ty))
+ blit(g, d, s, tysize(ty), tyalign(ty));
+ else
+ out(g, storeop(ty), Zq, s, d);
+ return d;
+}
+
+/*static*/ void checkidx(Gen *g, Qop op, Loc len, Loc idx)
+{
+ char ok[128], fail[128];
+ Loc oklbl, faillbl;
+ Loc inrange;
+
+ genlblstr(ok, sizeof ok, "");
+ genlblstr(fail, sizeof fail, "");
+
+ inrange = qtemp(g, 'w');
+ oklbl = qlabelstr(g, strdup(fail));
+ faillbl = qlabelstr(g, strdup(fail));
+
+ out(g, op, inrange, len, idx);
+ out(g, Qjnz, inrange, oklbl, faillbl);
+ out(g, Qlabel, faillbl, Zq, Zq);
+ ocall(g, abortoob, Zq, Zq, NULL, NULL, 0);
+ out(g, Qlabel, oklbl, Zq, Zq);
+}
+
+static Loc
+loadvar(Gen *g, Node *var)
+{
+ Node *dcl;
+ Type *ty;
+ Loc r, l;
+
+ dcl = decls[var->expr.did];
+ ty = tybase(exprtype(var));
+ l = qvar(g, dcl);
+ if (isstacktype(ty)) {
+ r = l;
+ } else {
+ r = qtemp(g, l.tag);
+ if (ty->type != Tyvoid)
+ out(g, loadop(ty), r, l, Zq);
+ }
+ return r;
+}
+
+static Loc
+deref(Gen *g, Node *n)
+{
+ Loc l, r;
+ Type *ty;
+
+ ty = exprtype(n);
+ l = rval(g, n);
+ if (isstacktype(ty))
+ return l;
+ r = qtemp(g, qtag(g, ty));
+ out(g, loadop(ty), r, l, Zq);
+ return r;
+}
+
+static size_t
+countargs(Type *t)
+{
+ size_t n, i;
+
+ n = 0;
+ t = tybase(t);
+ for (i = 1; i < t->nsub; i++) {
+ if (tybase(t->sub[i])->type == Tyvalist)
+ break;
+ if (tybase(t->sub[i])->type != Tyvoid)
+ n++;
+ }
+ return n;
+}
+
+static Type *
+vatype(Gen *g, Srcloc l, Node **al, size_t na)
+{
+ Type **t;
+ size_t i, nt;
+
+ nt = 0;
+ t = NULL;
+ for (i = 0; i < na; i++) {
+ lappend(&t, &nt, exprtype(al[i]));
+ }
+ return mktytuple(l, t, nt);
+}
+
+static Loc
+vablob(Gen *g, Srcloc l, Type *t)
+{
+ Node *d;
+ Type *tt, *tl[2];
+
+ tl[0] = mktype(l, Tyuint64);
+ tl[1] = t;
+ tt = mktytuple(l, tl, 2);
+ gentemp(l, tt, &d);
+ addlocal(g, d);
+ return qvar(g, d);
+}
+
+static Loc
+genvarargs(Gen *g, Srcloc l, Node **al, size_t na, Type **t)
+{
+ size_t i, sz, a, off;
+ Loc va, s, d;
+ Type *ty, *tt;
+ Blob *b;
+
+ /* genrate varargs */
+ sz = Ptrsz; /* tydesc */
+ for (i = 0; i < na; i++) {
+ a = min(size(al[i]), Ptrsz);
+ sz = align(sz, a);
+ sz += size(al[i]);
+ }
+ tt = vatype(g, l, al, na);
+ b = tydescblob(tt);
+ tagreflect(tt);
+ va = vablob(g, l, tt);
+ off =Ptrsz;
+ d = qtemp(g, 'l');
+ out(g, Qstorel, Zq, qblob(g, b), va);
+ out(g, Qadd, d, va, ptrsize);
+ for (i = 0; i < na; i++) {
+ ty = exprtype(al[i]);
+ off = align(off, tyalign(ty));
+ s = rval(g, al[i]);
+ d = qtemp(g, 'l');
+ out(g, Qadd, d, va, qconst(g, off, 'l'));
+ if (isstacktype(ty))
+ blit(g, d, s, tysize(ty), tyalign(ty));
+ else
+ out(g, storeop(ty), Zq, s, d);
+ off += tysize(ty);
+ }
+
+ lappend(&g->vatype, &g->nvatype, tt);
+ g->typenames = xrealloc(g->typenames, ntypes * sizeof(Type*));
+ g->typenames[tt->tid] = strfmt(":t%d", tt->tid);
+
+ *t = tt;
+ return va;
+}
+
+static Loc
+gencall(Gen *g, Node *n)
+{
+ Type **tl, *ft, *vt, *ty;
+ size_t nva, na, i;
+ Loc env, ret, fn;
+ Loc *al;
+ Node **va;
+
+ ft = exprtype(n->expr.args[0]);
+ al = xalloc(ft->nsub * sizeof(Loc));
+ tl = xalloc(ft->nsub * sizeof(Type *));
+ va = n->expr.args + (ft->nsub - 1);
+ nva = n->expr.nargs - (ft->nsub - 1);
+
+ ret = Zq;
+ env = Zq;
+ if (tybase(exprtype(n))->type != Tyvoid)
+ ret = temp(g, n);
+
+ na = countargs(ft);
+ /* +1 to skip past the function */
+ for (i = 1; i <= na; i++) {
+ ty = exprtype(n->expr.args[i]);
+ ty = tybase(ty);
+ if (ty->type == Tyvoid) {
+ rval(g, n->expr.args[i]);
+ continue;
+ }
+ al[i - 1] = rval(g, n->expr.args[i]);
+ tl[i - 1] = ty;
+ }
+ if (ft->sub[ft->nsub - 1]->type == Tyvalist) {
+ al[i - 1] = genvarargs(g, n->loc, va, nva, &vt);
+ tl[i - 1] = vt;
+ na++;
+ }
+ fn = rval(g, n->expr.args[0]);
+
+ ocall(g, fn, ret, env, al, tl, na);
+ return ret;
+}
+
+static void
+checkbounds(Gen *g, Node *n, Loc len)
+{
+}
+
+ssize_t
+memboff(Gen *g, Type *ty, Node *memb)
+{
+ size_t i;
+ size_t off;
+
+ ty = tybase(ty);
+ if (ty->type == Typtr)
+ ty = tybase(ty->sub[0]);
+
+ assert(ty->type == Tystruct);
+ off = 0;
+ for (i = 0; i < ty->nmemb; i++) {
+ off = alignto(off, decltype(ty->sdecls[i]));
+ if (!strcmp(namestr(memb), declname(ty->sdecls[i])))
+ return off;
+ off += size(ty->sdecls[i]);
+ }
+ die("bad member in offset");
+ return 0;
+}
+
+static Loc
+membaddr(Gen *g, Node *n)
+{
+ Type *t;
+ Loc b, r;
+ size_t o;
+
+ t = exprtype(n->expr.args[0]);
+ b = rval(g, n->expr.args[0]);
+ o = memboff(g, t, n->expr.args[1]);
+ r = qtemp(g, 'l');
+ out(g, Qadd, r, b, qconst(g, o, 'l'));
+ return r;
+}
+
+static Loc
+seqbase(Gen *g, Node *slnode, Node *offnode)
+{
+ Loc u, v, r;
+ Type *ty;
+ size_t sz;
+ Loc sl, off;
+
+ ty = tybase(exprtype(slnode));
+ sl = rval(g, slnode);
+ switch (ty->type) {
+ case Typtr: u = sl; break;
+ case Tyarray: u = sl; break;
+ case Tyslice:
+ u = qtemp(g, 'l');
+ out(g, Qloadl, u, sl, Zq);
+ break;
+ default:
+ die("Unslicable type %s", tystr(ty));
+ }
+ /* safe: all types we allow here have a sub[0] that we want to grab */
+ if (!offnode)
+ return u;
+ off = ptrsized(g, rval(g, offnode));
+ sz = tysize(slnode->expr.type->sub[0]);
+ v = qtemp(g, 'l');
+ r = qtemp(g, 'l');
+ out(g, Qmul, v, off, qconst(g, sz, 'l'));
+ out(g, Qadd, r, u, v);
+ return r;
+}
+
+static Loc
+genslice(Gen *g, Node *n)
+{
+ Node *arg, *off, *lim;
+ Loc lo, hi, start, sz;
+ Loc base, p, len;
+ Loc sl, lenp;
+ Type *ty;
+
+
+ arg = n->expr.args[0];
+ off = n->expr.args[1];
+ lim = n->expr.args[1];
+ ty = exprtype(arg);
+ sl = qstacktemp(g, n);
+ lenp = qtemp(g, 'l');
+ out(g, Qadd, lenp, sl, ptrsize);
+ /* Special case: Literal arrays with 0 need to be
+ have zero base pointers and lengths in order to
+ act as nice initializers */
+ if (exprop(arg) == Oarr && arg->expr.nargs == 0) {
+ base = qconst(g, 0, 'l');
+ } else {
+ base = seqbase(g, arg, off);
+ }
+ lo = rval(g, off);
+ if (lo.tag != 'l')
+ lo = intcvt(g, lo, 'l', size(off), 1);
+ hi = rval(g, lim);
+ if (hi.tag != 'l')
+ hi = intcvt(g, hi, 'l', size(lim), 1);
+ sz = qconst(g, tysize(ty->sub[0]), 'l');
+ len = qtemp(g, 'l');
+ start = qtemp(g, 'l');
+
+ p = qtemp(g, 'l');
+ out(g, Qadd, p, base, lo);
+ out(g, Qsub, len, hi, lo);
+ out(g, Qmul, start, len, sz);
+
+ checkbounds(g, n, len);
+ out(g, Qstorel, Zq, p, sl);
+ out(g, Qstorel, Zq, len, lenp);
+ return sl;
+}
+
+static Loc
+genucon(Gen *g, Node *n)
+{
+ Loc u, tag, dst, elt, align;
+ size_t sz, al;
+ Type *ty;
+ Ucon *uc;
+
+ ty = tybase(exprtype(n));
+ uc = finducon(ty, n->expr.args[0]);
+ if (!uc)
+ die("Couldn't find union constructor");
+
+ u = qstacktemp(g, n);
+ tag = qconst(g, uc->id, 'w');
+ out(g, Qstorew, Zq, tag, u);
+ if (!uc->etype)
+ return u;
+
+ al = max(4, tyalign(uc->etype));
+ sz = tysize(uc->etype);
+ dst = qtemp(g, 'l');
+ align = qconst(g, al, 'l');
+ out(g, Qadd, dst, u, align);
+
+ elt = rval(g, n->expr.args[1]);
+ if (isstacktype(uc->etype))
+ blit(g, dst, elt, sz, al);
+ else
+ out(g, storeop(uc->etype), Zq, elt, dst);
+ return u;
+}
+
+static Blob *
+strblob(Gen *g, Str s)
+{
+ Blob **v, *d, *b;
+ char buf[128];
+
+ d = mkblobbytes(s.buf, s.len);
+ d->lbl = strdup(genlblstr(buf, sizeof buf, ""));
+ lappend(&g->blobs, &g->nblobs, d);
+ v = xalloc(2*sizeof(Blob*));
+ v[0] = mkblobref(d->lbl, 0, 0);
+ v[1] = mkblobi(Bti64, s.len);
+ b = mkblobseq(v, 2);
+ b->lbl = strdup(genlblstr(buf, sizeof buf, ""));
+ lappend(&g->blobs, &g->nblobs, b);
+ return b;
+}
+
+static Loc
+strlabel(Gen *g, Node *s)
+{
+ Blob *b;
+
+ b = strblob(g, s->lit.strval);
+ return qblob(g, b);
+}
+
+static int
+envcmp(const void *pa, const void *pb)
+{
+ const Node *a, *b;
+
+ a = *(const Node**)pa;
+ b = *(const Node**)pb;
+ return b->decl.did - a->decl.did;
+}
+
+static Loc
+code(Gen *g, Node *fn)
+{
+ Node *d, *n;
+ char lbl[128];
+
+ n = mkname(fn->loc, genlblstr(lbl, 128, ""));
+ d = mkdecl(fn->loc, n, exprtype(fn));
+
+ d->decl.type = exprtype(fn);
+ d->decl.init = fn;
+ d->decl.isconst = 1;
+ d->decl.isglobl = 1;
+
+ lappend(&file->file.stmts, &file->file.nstmts, d);
+ return qvar(g, d);
+}
+
+static Loc
+capture(Gen *g, Node *n, Node *fn)
+{
+ size_t nenv, nenvt, off, i;
+ Loc f, e, s, d, fp;
+ Type **envt, *t;
+ Node **env, *dcl;
+
+ fp = qstacktemp(g, n);
+ env = getclosure(fn->func.scope, &nenv);
+ if (env && 0) {
+ /* we need these in a deterministic order so that we can
+ put them in the right place both when we use them and
+ when we capture them. */
+ qsort(env, nenv, sizeof(Node*), envcmp);
+
+ /* make the tuple type that will hold the environment */
+ envt = NULL;
+ nenvt = 0;
+ /* reserve space for size */
+ lappend(&envt, &nenvt, mktype(n->loc, Tyuint64));
+ for (i = 0; i < nenv; i++)
+ lappend(&envt, &nenvt, decltype(env[i]));
+
+ gentemp(n->loc, mktytuple(n->loc, envt, nenvt), &dcl);
+ e = qstacktemp(g, dcl);
+ d = qtemp(g, 'l');
+ off = Ptrsz; /* we start with the size of the env */
+ for (i = 0; i < nenv; i++) {
+ off = alignto(off, decltype(env[i]));
+ t = decltype(env[i]);
+ s = qvar(g, env[i]);
+ out(g, Qadd, d, e, qconst(g, off, 'l'));
+ blit(g, d, s, tysize(t), tyalign(t));
+ off += size(env[i]);
+ }
+ free(env);
+ out(g, Qstorel, Zq, qconst(g, off, 'l'), e);
+ out(g, Qstorel, Zq, e, fp);
+ }
+ f = code(g, n);
+ out(g, Qadd, fp, fp, qconst(g, Ptrsz, 'l'));
+ out(g, Qstorel, Zq, f, fp);
+ return fp;
+}
+
+static Loc
+loadlit(Gen *g, Node *e)
+{
+ Node *n;
+ char t;
+
+ t = qtag(g, exprtype(e));
+ n = e->expr.args[0];
+ switch (n->lit.littype) {
+ case Llbl: return qlabel(g, n); break;
+ case Lstr: return strlabel(g, n); break;
+ case Lchr: return qconst(g, n->lit.chrval, t); break;
+ case Lbool: return qconst(g, n->lit.boolval, t); break;
+ case Lint: return qconst(g, n->lit.intval, t); break;
+ case Lflt: return qconst(g, n->lit.fltval, t); break;
+ case Lvoid: return qconst(g, n->lit.chrval, t); break;
+ case Lfunc: return capture(g, e, n->lit.fnval); break;
+ }
+ die("unreachable");
+ return Zq;
+}
+
+Loc
+rval(Gen *g, Node *n)
+{
+ Node **args, *a;
+ Type *ty, *ety;
+ size_t i, o, idx;
+ Loc r, l;
+ Loc d, s;
+ Op op;
+
+ r = Zq;
+ args = n->expr.args;
+ op = exprop(n);
+ switch (op) {
+ /* arithmetic */
+ case Oadd: r = binop(g, Qadd, args[0], args[1]); break;
+ case Osub: r = binop(g, Qsub, args[0], args[1]); break;
+ case Omul: r = binop(g, Qmul, args[0], args[1]); break;
+ case Odiv: r = binop(g, Qdiv, args[0], args[1]); break;
+ case Omod: r = binop(g, Qrem, args[0], args[1]); break;
+ case Ofadd: r = binop(g, Qadd, args[0], args[1]); break;
+ case Ofsub: r = binop(g, Qsub, args[0], args[1]); break;
+ case Ofmul: r = binop(g, Qmul, args[0], args[1]); break;
+ case Ofdiv: r = binop(g, Qdiv, args[0], args[1]); break;
+ case Obor: r = binop(g, Qor, args[0], args[1]); break;
+ case Oband: r = binop(g, Qand, args[0], args[1]); break;
+ case Obxor: r = binop(g, Qxor, args[0], args[1]); break;
+ case Obsl: r = binop(g, Qshl, args[0], args[1]); break;
+ case Obsr:
+ if (istysigned(exprtype(n)))
+ r = binop(g, Qshr, args[0], args[1]);
+ else
+ r = binop(g, Qshl, args[0], args[1]);
+ break;
+ case Obnot:
+ r = qtemp(g, qtag(g, exprtype(n)));
+ l = qconst(g, ~0, qtag(g, exprtype(n)));
+ out(g, Qxor, r, rval(g, args[0]), l);
+ break;
+ case Oneg:
+ case Ofneg:
+ r = qtemp(g, qtag(g, exprtype(n)));
+ l = qconst(g, 0, qtag(g, exprtype(n)));
+ out(g, Qsub, r, l, rval(g, args[0]));
+ break;
+
+ /* comparisons */
+ case Oeq: r = cmpop(g, op, args[0], args[1]); break;
+ case One: r = cmpop(g, op, args[0], args[1]); break;
+ case Ogt: r = cmpop(g, op, args[0], args[1]); break;
+ case Oge: r = cmpop(g, op, args[0], args[1]); break;
+ case Olt: r = cmpop(g, op, args[0], args[1]); break;
+ case Ole: r = cmpop(g, op, args[0], args[1]); break;
+ case Ofeq: r = cmpop(g, op, args[0], args[1]); break;
+ case Ofne: r = cmpop(g, op, args[0], args[1]); break;
+ case Ofgt: r = cmpop(g, op, args[0], args[1]); break;
+ case Ofge: r = cmpop(g, op, args[0], args[1]); break;
+ case Oflt: r = cmpop(g, op, args[0], args[1]); break;
+ case Ofle: r = cmpop(g, op, args[0], args[1]); break;
+ case Oueq: r = cmpop(g, op, args[0], args[1]); break;
+ case Oune: r = cmpop(g, op, args[0], args[1]); break;
+ case Ougt: r = cmpop(g, op, args[0], args[1]); break;
+ case Ouge: r = cmpop(g, op, args[0], args[1]); break;
+ case Oult: r = cmpop(g, op, args[0], args[1]); break;
+ case Oule: r = cmpop(g, op, args[0], args[1]); break;
+
+ case Oasn: r = assign(g, args[0], args[1]); break;
+
+ case Oslbase: r = seqbase(g, args[0], args[1]); break;
+ case Osllen: r = slicelen(g, args[0], exprtype(n)); break;
+ case Oslice: r = genslice(g, n); break;
+
+ case Ocast: r = simpcast(g, args[0], exprtype(n)); break;
+ case Ocall: r = gencall(g, n); break;
+
+ case Ovar: r = loadvar(g, n); break;
+ case Olit: r = loadlit(g, n); break;
+ case Osize: r = qconst(g, size(args[0]), 'l'); break;
+ case Ojmp: out(g, Qjmp, qlabel(g, args[0]), Zq, Zq); break;
+ case Oidx:
+ ty = exprtype(n);
+ s = seqbase(g, args[0], args[1]);
+ if (isstacktype(ty)) {
+ r = s;
+ } else {
+ r = temp(g, n);
+ out(g, loadop(ty), r, s, Zq);
+ }
+ break;
+ case Oret:
+ ty = tybase(exprtype(args[0]));
+ if (ty->type != Tyvoid)
+ assign(g, g->retval, args[0]);
+ out(g, Qjmp, g->retlbl, Zq, Zq);
+ break;
+
+ case Oderef:
+ ty = tybase(exprtype(n));
+ if (isstacktype(ty)) {
+ r = rval(g, args[0]);
+ } else {
+ r = temp(g, n);
+ out(g, loadop(ty), r, rval(g, args[0]), Zq);
+ }
+ break;
+ case Oaddr:
+ ty = tybase(exprtype(args[0]));
+ if (exprop(n) == Ovar)
+ r = qvar(g, n);
+ else
+ r = lval(g, args[0]);
+ break;
+
+ case Ocjmp:
+ out(g, Qjnz, rval(g, args[0]), qlabel(g, args[1]), qlabel(g, args[2]));
+ break;
+
+ case Outag:
+ l = rval(g, args[0]);
+ r = qtemp(g, 'w');
+ out(g, Qloadw, r, l, Zq);
+ break;
+
+ case Oucon:
+ r = genucon(g, n);
+ break;
+
+ case Ostruct:
+ r = qstacktemp(g, n);
+ d = r;
+ o = 0;
+ ety = exprtype(n);
+ for (i = 0; i < n->expr.nargs; i++) {
+ a = n->expr.args[i];
+ ty = exprtype(a);
+
+ s = rval(g, a);
+ o = memboff(g, ety, a->expr.idx);
+ out(g, Qadd, d, d, qconst(g, o, 'l'));
+ if (isstacktype(ty))
+ blit(g, d, s, tysize(ty), tyalign(ty));
+ else
+ out(g, storeop(ty), Zq, s, d);
+ }
+ break;
+
+ /* Otup and Oarr have a similar enough structure that this works */
+ case Oarr:
+ case Otup:
+ r = qstacktemp(g, n);
+ d = r;
+ o = 0;
+ ety = exprtype(n);
+ for (i = 0; i < n->expr.nargs; i++) {
+ a = n->expr.args[i];
+ ty = exprtype(a);
+
+ o = alignto(o, ty);
+ s = rval(g, a);
+ out(g, Qadd, d, d, qconst(g, o, 'l'));
+ if (isstacktype(ty))
+ blit(g, d, s, tysize(ty), tyalign(ty));
+ else
+ out(g, storeop(ty), Zq, s, d);
+ o += tysize(ty);
+ }
+ break;
+
+ case Omemb:
+ ty = exprtype(n);
+ l = membaddr(g, n);
+ if (isstacktype(ty)) {
+ r = l;
+ } else {
+ r = qtemp(g, qtag(g, ty));
+ out(g, loadop(ty), r, l, Zq);
+ }
+ break;
+ case Oudata:
+ ty = exprtype(n->expr.args[0]);
+ s = rval(g, n->expr.args[0]);
+ r = qtemp(g, 'l');
+ out(g, Qadd, r, s, qconst(g, Ptrsz, 'l'));
+ break;
+
+ case Otupget:
+ assert(exprop(args[1]) == Olit);
+ s = rval(g, args[0]);
+ ty = exprtype(n);
+ o = 0;
+ idx = args[1]->expr.args[0]->lit.intval;
+ for (i = 0; i < ty->nsub; i++) {
+ o = alignto(o, ty->sub[i]);
+ if (i == idx)
+ break;
+ o += tysize(ty->sub[i]);
+ }
+ l = qtemp(g, 'l');
+ out(g, Qadd, l, s, qconst(g, o, 'l'));
+ if (isstacktype(ty)) {
+ r = l;
+ } else {
+ r = qtemp(g, qtag(g, ty));
+ out(g, loadop(ty), r, l, Zq);
+ }
+ break;
+ case Olnot:
+ ty = exprtype(n);
+ l = rval(g, args[0]);
+ r = qtemp(g, qtag(g, ty));
+ if (r.tag == 'w')
+ out(g, Qceqw, r, l, qconst(g, 0, r.tag));
+ else
+ out(g, Qceql, r, l, qconst(g, 0, r.tag));
+ break;
+ case Ocallind:
+ case Ovjmp:
+ die("unimplemented operator %s", opstr[exprop(n)]);
+ break;
+
+ case Odead:
+ case Oundef:
+ case Odef:
+ break;
+
+ /* should not be generated by middle end */
+ case Oset:
+ case Oblit:
+ case Otrunc:
+ case Ozwiden:
+ case Oswiden:
+ case Oflt2int:
+ case Oint2flt:
+ case Oflt2flt:
+ case Oclear:
+ /* should be dealt with earlier */
+ case Olor: case Oland:
+ case Oaddeq: case Osubeq: case Omuleq: case Odiveq: case Omodeq:
+ case Oboreq: case Obandeq: case Obxoreq: case Obsleq: case Obsreq:
+ case Opreinc: case Opredec: case Opostinc: case Opostdec:
+ case Obreak: case Ocontinue:
+ case Numops: case Ogap:
+ die("invalid operator %s: should have been removed", opstr[exprop(n)]);
+ case Obad:
+ die("bad operator");
+ break;
+ }
+ return r;
+}
+
+static Loc
+lval(Gen *g, Node *n)
+{
+ Node **args;
+ Loc r;
+
+ args = n->expr.args;
+ switch (exprop(n)) {
+ case Oidx: r = seqbase(g, args[0], args[1]); break;
+ case Oderef: r = deref(g, args[0]); break;
+ case Ovar: r = qvar(g, n); break;
+ case Omemb: r = membaddr(g, n); break;
+ case Ostruct: r = rval(g, n); break;
+ case Oucon: r = rval(g, n); break;
+ case Oarr: r = rval(g, n); break;
+ case Ogap: r = temp(g, n); break;
+
+ /* not actually expressible as lvalues in syntax, but we generate them */
+ case Oudata: r = rval(g, n); break;
+ case Outag: r = rval(g, n); break;
+ case Otupget: r = rval(g, n); break;
+ default:
+ fatal(n, "%s cannot be an lvalue", opstr[exprop(n)]);
+ break;
+ }
+ return r;
+}
+
+void
+genbb(Gen *g, Cfg *cfg, Bb *bb)
+{
+ size_t i;
+
+ for (i = 0; i < bb->nlbls; i++)
+ out(g, Qlabel, qlabelstr(g, bb->lbls[i]), Zq, Zq);
+
+ for (i = 0; i < bb->nnl; i++) {
+ switch (bb->nl[i]->type) {
+ case Ndecl:
+ break;
+ case Nexpr:
+ rval(g, bb->nl[i]);
+ break;
+ default:
+ dump(bb->nl[i], stderr);
+ die("bad node passsed to simp()");
+ break;
+ }
+
+ }
+}
+
+void
+spillargs(Gen *g, Node *fn)
+{
+ Loc arg, val;
+ Type *ty;
+ Node *a;
+ size_t i;
+
+ g->arg = zalloc(fn->func.nargs * sizeof(Loc));
+ for (i = 0; i < fn->func.nargs; i++) {
+ a = fn->func.args[i];
+ ty = tybase(decltype(a));
+ if (ty->type == Tyvoid)
+ continue;
+ if (isstacktype(ty)) {
+ arg = qvar(g, a);
+ } else {
+ arg = qtemp(g, qtag(g, ty));
+ val = qvar(g, a);
+ out(g, storeop(ty), Zq, arg, val);
+ addlocal(g, a);
+ }
+ g->arg[i] = arg;
+ g->narg++;
+ }
+}
+
+void
+declare(Gen *g, Node *n)
+{
+ size_t align, size;
+ char *name;
+ Type *ty;
+
+ assert(n);
+ if (n->type == Nexpr && exprop(n) == Ovar)
+ n = decls[n->expr.did];
+ assert(n->type == Ndecl);
+ name = declname(n);
+ ty = decltype(n);
+ align = tyalign(ty);
+ size = tysize(ty);
+ fprintf(g->f, "\t%%%s =l alloc%zd %zd\n", name, align, size);
+}
+
+static const
+char *insnname[] = {
+#define Insn(name) #name,
+#include "qbe.def"
+#undef Insn
+};
+
+void
+emitloc(Gen *g, Loc l, char *sep)
+{
+ Node *d;
+ char *n;
+ char c;
+
+ if (!l.tag)
+ return;
+ switch (l.kind) {
+ case Lblob: fprintf(g->f, "$%s%s", l.blob->lbl, sep); break;
+ case Ltemp: fprintf(g->f, "%%.%lld%s", l.tmp, sep); break;
+ case Lconst: fprintf(g->f, "%lld%s", l.cst, sep); break;
+ case Llabel: fprintf(g->f, "@%s%s", l.lbl, sep); break;
+ case Ldecl:
+ d = decls[l.dcl];
+ c = d->decl.isglobl ? '$' : '%';
+ n = asmname(d->decl.name, c);
+ fprintf(g->f, "%s%s", n, sep);
+ free(n);
+ }
+}
+
+void
+emitinsn(Gen *g, Insn *insn)
+{
+ char *sep, *t;
+ size_t i;
+
+ if (insn->op != Qlabel)
+ fprintf(g->f, "\t");
+ switch (insn->op) {
+ case Qlabel:
+ emitloc(g, insn->ret, "");
+ break;
+ case Qjmp:
+ fprintf(g->f, "%s ", insnname[insn->op]);
+ emitloc(g, insn->ret, "");
+ break;
+ case Qjnz:
+ fprintf(g->f, "%s ", insnname[insn->op]);
+ emitloc(g, insn->ret, ", ");
+ emitloc(g, insn->arg[0], ", ");
+ emitloc(g, insn->arg[1], "");
+ break;
+ case Qcall:
+ emitloc(g, insn->ret, "");
+ if (insn->ret.tag)
+ fprintf(g->f, " =%c\t", insn->ret.tag);
+ else
+ fprintf(g->f, "\t");
+ fprintf(g->f, "%s\t", insnname[insn->op]);
+ emitloc(g, insn->fn, " ");
+ fprintf(g->f, "(");
+ for (i = 0; i < insn->nfarg; i++) {
+ sep = (i == insn->nfarg - 1) ? "" : ", ";
+ t = qtype(g, insn->fty[i]);
+ if (!strcmp(t, "b") || !strcmp(t, "h"))
+ t = "w";
+ fprintf(g->f, "%s ", t);
+ emitloc(g, insn->farg[i], sep);
+ }
+ fprintf(g->f, ")");
+ break;
+ default:
+ emitloc(g, insn->ret, "");
+ if (insn->ret.tag)
+ fprintf(g->f, "=%c\t", insn->ret.tag);
+ else
+ fprintf(g->f, "\t");
+ fprintf(g->f, "%s\t", insnname[insn->op]);
+ sep = insn->arg[1].tag ? ", " : "";
+ emitloc(g, insn->arg[0], sep);
+ emitloc(g, insn->arg[1], "");
+ break;
+ }
+ fprintf(g->f, "\n");
+}
+
+void
+emitfn(Gen *g, Node *d)
+{
+ Node *a, *n, *fn;
+ Type *ty, *rtype;
+ size_t i, arg;
+ char *x, *sep, *t, *name;
+
+ n = d->decl.init;
+ n = n->expr.args[0];
+ fn = n->lit.fnval;
+
+ for (i = 0; i < g->nvatype; i++) {
+ ty = g->vatype[i];
+ fprintf(g->f, "type :t%d = align %zd { %zd }\n",
+ ty->tid, tyalign(ty), tysize(ty) + Ptrsz);
+ }
+
+ rtype = tybase(g->rettype);
+ x = isexport(d) ? "export " : "";
+ name = asmname(d->decl.name, '$');
+ t = (rtype->type == Tyvoid) ? "" : qtype(g, rtype);
+ if (!strcmp(t, "b") || !strcmp(t, "h"))
+ t = "w";
+ fprintf(g->f, "%sfunction %s %s", x, t, name);
+ free(name);
+ fprintf(g->f, "(");
+ arg = 0;
+ for (i = 0; i < fn->func.nargs; i++) {
+ a = fn->func.args[i];
+ ty = tybase(decltype(a));
+ if (ty->type != Tyvoid) {
+ sep = (arg == g->narg - 1) ? "" : ", ";
+ t = qtype(g, ty);
+ if (!strcmp(t, "b") || !strcmp(t, "h"))
+ t = "w";
+ fprintf(g->f, "%s ", t);
+ emitloc(g, g->arg[arg++], sep);
+ }
+ }
+ fprintf(g->f, ")\n");
+ fprintf(g->f, "{\n");
+ fprintf(g->f, "@start\n");
+ if (g->retval)
+ declare(g, g->retval);
+ for (i = 0; i < g->nlocal; i++)
+ declare(g, g->local[i]);
+ for (i = 0; i < g->ninsn; i++)
+ emitinsn(g, &g->insn[i]);
+ fprintf(g->f, "}\n");
+}
+
+void
+genfn(Gen *g, Node *dcl)
+{
+ Node *n, *b, *retdcl;
+ size_t i;
+ Cfg *cfg;
+ Bb *bb;
+ Loc r;
+
+ if (dcl->decl.isextern || dcl->decl.isgeneric)
+ return;
+
+ n = dcl->decl.init;
+
+ /* set up the simp context */
+ /* unwrap to the function body */
+ //collectenv(s, n);
+ n = n->expr.args[0];
+ n = n->lit.fnval;
+ b = n->func.body;
+
+ cfg = mkcfg(dcl, b->block.stmts, b->block.nstmts);
+ check(cfg);
+ if (debugopt['t'] || debugopt['s'])
+ dumpcfg(cfg, stdout);
+
+ /* func declaration */
+ g->retval = NULL;
+ g->rettype = tybase(dcl->decl.type->sub[0]);
+ g->retlbl = qlabel(g, genlbl(dcl->loc));
+ lfree(&g->vatype, &g->nvatype);
+
+ if (tybase(g->rettype)->type != Tyvoid)
+ g->retval = gentemp(dcl->loc, g->rettype, &retdcl);
+ spillargs(g, n);
+ for (i = 0; i < cfg->nbb; i++) {
+ bb = cfg->bb[i];
+ if (!bb)
+ continue;
+ genbb(g, cfg, bb);
+ }
+ out(g, Qlabel, g->retlbl, Zq, Zq);
+ if (g->retval)
+ r = rval(g, g->retval);
+ else
+ r = Zq;
+ out(g, Qret, Zq, r, Zq);
+ emitfn(g, dcl);
+ g->ninsn = 0;
+ g->narg = 0;
+ free(g->arg);
+}
+
+void
+gendata(Gen *g)
+{
+ size_t i;
+
+ for (i = 0; i < g->nblobs; i++)
+ genblob(g, g->blobs[i]);
+}
+
+void
+gentydesc(Gen *g)
+{
+ Blob *b;
+ Type *ty;
+ size_t i;
+
+ for (i = Ntypes; i < ntypes; i++) {
+ if (!types[i]->isreflect)
+ continue;
+ ty = tydedup(types[i]);
+ if (ty->isemitted || ty->isimport)
+ continue;
+ ty->isemitted = 1;
+ b = tydescblob(ty);
+ b->iscomdat = 1;
+ genblob(g, b);
+ blobfree(b);
+ }
+ fprintf(g->f, "\n");
+}
+
+void
+outarray(Gen *g, Type *ty)
+{
+ size_t sz;
+
+ sz = 0;
+ if (ty->asize)
+ sz = ty->asize->expr.args[0]->lit.intval;
+ outtypebody(g, ty->sub[0]);
+ fprintf(g->f, "\t%s %zd,\n", qtype(g, ty->sub[0]), sz);
+}
+
+void
+outstruct(Gen *g, Type *ty)
+{
+ size_t i;
+ Type *mty;
+
+ for (i = 0; i < ty->nmemb; i++) {
+ mty = decltype(ty->sdecls[i]);
+ outtypebody(g, mty);
+ }
+}
+
+void
+outunion(Gen *g, Type *ty)
+{
+ size_t i;
+ Type *mty;
+ size_t maxalign;
+ size_t maxsize;
+
+ maxalign = 1;
+ maxsize = 0;
+ for (i = 0; i < ty->nmemb; i++) {
+ mty = ty->udecls[i]->etype;
+ if (!mty)
+ continue;
+ if (tyalign(mty) > maxalign)
+ maxalign = tyalign(mty);
+ if (tysize(mty) > maxsize)
+ maxsize = tysize(mty);
+ }
+ maxsize += align(4, maxalign);
+ fprintf(g->f, "%zd\n", maxsize);
+}
+
+void
+outtuple(Gen *g, Type *ty)
+{
+ size_t i;
+ Type *mty;
+
+ for (i = 0; i < ty->nsub; i++) {
+ mty = ty->sub[i];
+ outtypebody(g, mty);
+ fprintf(g->f, "\t%s,\n", qtype(g, mty));
+ }
+}
+
+void
+outtypebody(Gen *g, Type *ty)
+{
+ ty = tydedup(ty);
+ switch (ty->type) {
+ case Tyvoid: break;
+ case Tybool: fprintf(g->f, "\tb,\n"); break;
+ case Tychar: fprintf(g->f, "\tw,\n"); break;
+ case Tyint8: fprintf(g->f, "\tb,\n"); break;
+ case Tyint16: fprintf(g->f, "\th,\n"); break;
+ case Tyint: fprintf(g->f, "\tw,\n"); break;
+ case Tyint32: fprintf(g->f, "\tw,\n"); break;
+ case Tyint64: fprintf(g->f, "\tl,\n"); break;
+ case Tybyte: fprintf(g->f, "\tb,\n"); break;
+ case Tyuint8: fprintf(g->f, "\tb,\n"); break;
+ case Tyuint16: fprintf(g->f, "\th,\n"); break;
+ case Tyuint: fprintf(g->f, "\tw,\n"); break;
+ case Tyuint32: fprintf(g->f, "\tw,\n"); break;
+ case Tyuint64: fprintf(g->f, "\tl,\n"); break;
+ case Tyflt32: fprintf(g->f, "\ts,\n"); break;
+ case Tyflt64: fprintf(g->f, "\td,\n"); break;
+ case Typtr: fprintf(g->f, "\tl,\n"); break;
+ case Tyslice: fprintf(g->f, "\tl, l,\n"); break;
+ case Tycode: fprintf(g->f, "\tl,\n"); break;
+ case Tyfunc: fprintf(g->f, "\tl, l,\n"); break;
+ case Tyvalist: fprintf(g->f, "\tl\n"); break;
+ case Tyarray: outarray(g, ty); break;
+ case Tystruct: outstruct(g, ty); break;
+ case Tytuple: outtuple(g, ty); break;
+ case Tyunion: outunion(g, ty); break;
+ case Tyname: fprintf(g->f, "\t:t%d,\n", ty->tid); break;
+
+ /* frontend/invalid types */
+ case Tyvar:
+ case Tybad:
+ case Typaram:
+ case Tyunres:
+ case Tygeneric:
+ case Ntypes:
+ die("invalid type %s");
+ break;
+ }
+}
+
+static void
+outstructtype(Gen *g, Type *ty)
+{
+ size_t i;
+
+ for (i = 0; i < ty->nmemb; i++)
+ outqtype(g, decltype(ty->sdecls[i]));
+}
+
+static void
+outtupletype(Gen *g, Type *ty)
+{
+ size_t i;
+
+ for (i = 0; i < ty->nsub; i++)
+ outqtype(g, ty->sub[i]);
+}
+
+
+static void
+outuniontype(Gen *g, Type *ty)
+{
+ size_t i;
+ Type *mty;
+
+ for (i = 0; i < ty->nmemb; i++) {
+ mty = ty->udecls[i]->etype;
+ if (!mty)
+ continue;
+ outqtype(g, mty);
+ }
+}
+
+static void
+outqtype(Gen *g, Type *t)
+{
+ char buf[1024];
+ Type *ty;
+ Ty tt;
+
+ ty = tydedup(t);
+ tt = ty->type;
+ if (tt == Tycode || tt == Tyvar || tt == Tyunres || hasparams(ty))
+ return;
+ if (!istyconcrete(ty))
+ return;
+ if (ty->vis == Visbuiltin)
+ return;
+ if (g->typenames[ty->tid]) {
+ g->typenames[t->tid] = g->typenames[ty->tid];
+ return;
+ }
+
+ snprintf(buf, sizeof buf, ":t%d", ty->tid);
+ g->typenames[ty->tid] = strdup(buf);
+
+ switch (tt) {
+ case Tyarray: outqtype(g, ty->sub[0]); break;
+ case Tystruct: outstructtype(g, ty); break;
+ case Tytuple: outtupletype(g, ty); break;
+ case Tyunion: outuniontype(g, ty); break;
+ case Tyname: outqtype(g, ty->sub[0]); break;
+ default:
+ break;
+ }
+
+ fprintf(g->f, "type %s = align %zd {\n", g->typenames[ty->tid], tyalign(ty));
+ if (tt != Tyname)
+ outtypebody(g, ty);
+ else
+ outtypebody(g, ty->sub[0]);
+ fprintf(g->f, "}\n\n");
+}
+
+
+static void
+genqtypes(Gen *g)
+{
+ size_t i;
+
+ g->typenames = zalloc(ntypes * sizeof(Type *));
+ g->typenames[Tyvalist] = ":.vablob";
+ fprintf(g->f, "type :.vablob = align 8 { 8 }\n");
+ for (i = Ntypes; i < ntypes; i++) {
+ outqtype(g, types[i]);
+ }
+}
+
+static void
+genglobl(Gen *g, Node *dcl)
+{
+ char *s, *x;
+ Node *e;
+ Blob *b;
+ Type *t;
+
+
+ e = dcl->decl.init;
+ e = fold(e, 1);
+ if (e) {
+ dcl->decl.init = e;
+ b = mkblobseq(NULL, 0);
+ blobrec(g, b, e);
+ } else {
+ t = decltype(dcl);
+ b = mkblobpad(tysize(t));
+ }
+
+
+ s = asmname(dcl->decl.name, '$');
+ x = isexport(dcl) ? "export " : "";
+ fprintf(g->f, "%sdata %s = {\n", x, s);
+ genblob(g, b);
+ fprintf(g->f, "}\n\n");
+ free(s);
+}
+
+void
+gen(Node *file, char *out)
+{
+ Htab *globls;
+ Node **locals;
+ size_t nlocals;
+ Node *n;
+ Gen *g;
+ size_t i;
+
+ /* generate the code */
+ g = zalloc(sizeof(Gen));
+ g->f = fopen(out, "w");
+ if (!g->f)
+ die("Couldn't open fd %s", out);
+ /* set up code gen state */
+ globls = mkht(varhash, vareq);
+ initconsts(g, globls);
+ fillglobls(file->file.globls, globls);
+
+ g->globls = mkht(varhash, vareq);
+
+ genqtypes(g);
+ pushstab(file->file.globls);
+ for (i = 0; i < file->file.nstmts; i++) {
+ n = file->file.stmts[i];
+ switch (n->type) {
+ case Nuse:
+ case Nimpl
+ /* nothing to do */ :
+ break;
+ case Ndecl:
+ if (n->decl.isgeneric)
+ break;
+ if (isconstfn(n)) {
+ n = flattenfn(n, &locals, &nlocals);
+ g->local = locals;
+ g->nlocal = nlocals;
+ genfn(g, n);
+ } else {
+ genglobl(g, n);
+ }
+ break;
+ default:
+ die("Bad node %s in toplevel", nodestr[n->type]);
+ break;
+ }
+ }
+ popstab();
+ gendata(g);
+ gentydesc(g);
+ fclose(g->f);
+}
diff --git a/6q/main.c b/6q/main.c
new file mode 100644
index 0000000..d8673e8
--- /dev/null
+++ b/6q/main.c
@@ -0,0 +1,303 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include "util.h"
+#include "parse.h"
+#include "mi.h"
+#include "qasm.h"
+
+#include "../config.h"
+
+/* FIXME: move into one place...? */
+Node *file;
+char debugopt[128];
+int writeasm;
+char *outfile;
+char *objdir;
+char **incpaths;
+char *localincpath;
+size_t nincpaths;
+
+static void
+usage(char *prog)
+{
+ printf("%s [-?|-h] [-o outfile] [-d[dbgopts]] inputs\n", prog);
+ printf("\t-?|-h\tPrint this help\n");
+ printf("\t-o\tOutput to outfile\n");
+ printf("\t-S\tGenerate assembly source alongside object code\n");
+ printf("\t-I path\tAdd 'path' to use search path\n");
+ printf("\t-d opts: additional debug logging. Options are listed below:\n");
+ printf("\t\tf: log folded trees\n");
+ printf("\t\tl: log lowered pre-cfg trees\n");
+ printf("\t\tT: log tree immediately\n");
+ printf("\t\tr: log register allocation activity\n");
+ printf("\t\ti: log instruction selection activity\n");
+ printf("\t\tu: log type unifications\n");
+}
+
+static void
+swapout(char* buf, size_t sz, char* suf) {
+ char* psuffix;
+ psuffix = strrchr(outfile, '.');
+ if (psuffix != NULL)
+ swapsuffix(buf, sz, outfile, psuffix, suf);
+ else
+ bprintf(buf, sz, "%s%s", outfile, suf);
+}
+
+static void
+assemble(char *qbesrc, char *asmsrc, char *path)
+{
+ char *qbecmd[] = {"qbe", "-o", NULL};
+ char *asmcmd[] = Asmcmd;
+ char objfile[1024];
+ char *psuffix;
+ char **p, **cmd;
+ size_t ncmd, i;
+ int pid, status;
+
+ if (outfile != NULL)
+ strncpy(objfile, outfile, 1024);
+ else {
+ psuffix = strrchr(path, '+');
+ i = 0;
+ if (objdir)
+ i = bprintf(objfile, sizeof objfile, "%s/", objdir);
+ if (psuffix != NULL)
+ swapsuffix(objfile + i, sizeof objfile, path, psuffix, Objsuffix);
+ else
+ swapsuffix(objfile + i, sizeof objfile, path, ".myr", Objsuffix);
+ }
+ cmd = NULL;
+ ncmd = 0;
+ for (p = qbecmd; *p != NULL; p++)
+ lappend(&cmd, &ncmd, *p);
+ lappend(&cmd, &ncmd, asmsrc);
+ lappend(&cmd, &ncmd, qbesrc);
+ lappend(&cmd, &ncmd, NULL);
+
+ for (p = cmd; *p; p++)
+ printf("%s ", *p);
+ printf("\n");
+
+ pid = fork();
+ if (pid == -1) {
+ die("couldn't fork");
+ } else if (pid == 0) {
+ if (execvp(cmd[0], cmd) == -1)
+ die("Couldn't exec qbe\n");
+ } else {
+ waitpid(pid, &status, 0);
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ die("Couldn't run qbe\n");
+ }
+ lfree(&cmd, &ncmd);
+
+ cmd = NULL;
+ ncmd = 0;
+ for (p = asmcmd; *p != NULL; p++)
+ lappend(&cmd, &ncmd, *p);
+ lappend(&cmd, &ncmd, objfile);
+ lappend(&cmd, &ncmd, asmsrc);
+ lappend(&cmd, &ncmd, NULL);
+
+ for (p = cmd; *p; p++)
+ printf("%s ", *p);
+ printf("\n");
+ pid = fork();
+ if (pid == -1) {
+ die("couldn't fork");
+ } else if (pid == 0) {
+ if (execvp(cmd[0], cmd) == -1)
+ die("Couldn't exec assembler\n");
+ } else {
+ waitpid(pid, &status, 0);
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ die("Couldn't run assembler");
+ }
+ lfree(&cmd, &ncmd);
+}
+
+static char *
+dirname(char *path)
+{
+ char *p;
+
+ p = strrchr(path, '/');
+ if (p)
+ return strdupn(path, p - path);
+ else
+ return xstrdup(".");
+}
+static char *
+gentempfile(char *buf, size_t bufsz, char *path, char *suffix)
+{
+ char *tmpdir;
+ char *base;
+ struct timeval tv;
+
+ tmpdir = getenv("TMPDIR");
+ if (!tmpdir)
+ tmpdir = "/tmp";
+ base = strrchr(path, '/');
+ if (base)
+ base++;
+ else
+ base = path;
+ gettimeofday(&tv, NULL);
+ bprintf(buf, bufsz, "%s/tmp%lx%lx-%s%s",
+ tmpdir, (long)tv.tv_sec, (long)tv.tv_usec, base, suffix);
+ return buf;
+}
+
+static int
+hasmain()
+{
+ Node *n, *name;
+
+ name = mknsname(Zloc, "", "main");
+ n = getdcl(file->file.globls, name);
+ if (!n)
+ return 0;
+ n = n->decl.name;
+ if (n->name.ns)
+ return 0;
+ return 1;
+}
+
+static void
+genuse(char *path)
+{
+ FILE *f;
+ char buf[1024];
+ char *psuffix;
+ size_t i;
+
+ if (outfile != NULL)
+ swapout(buf, 1024, ".use");
+ else {
+ psuffix = strrchr(path, '+');
+ i = 0;
+ if (objdir)
+ i = bprintf(buf, sizeof buf, "%s/", objdir);
+ if (psuffix != NULL)
+ swapsuffix(buf + i, sizeof buf, path, psuffix, ".use");
+ else
+ swapsuffix(buf + i, sizeof buf, path, ".myr", ".use");
+ }
+ f = fopen(buf, "w");
+ if (!f) {
+ fprintf(stderr, "Could not open path %s\n", buf);
+ exit(1);
+ }
+ writeuse(f, file);
+ fclose(f);
+}
+
+int
+main(int argc, char **argv)
+{
+ char qsbuf[256];
+ char asbuf[256];
+ Stab *globls;
+ Optctx ctx;
+ size_t i;
+
+ outfile = NULL;
+
+ optinit(&ctx, "cd:?hSo:I:9G:", argv, argc);
+ while (!optdone(&ctx)) {
+ switch (optnext(&ctx)) {
+ case 'O':
+ objdir = ctx.optarg;
+ break;
+ case 'o':
+ outfile = ctx.optarg;
+ break;
+ case 'S':
+ writeasm = 1;
+ break;
+ case '?':
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ break;
+ case 'd':
+ while (ctx.optarg && *ctx.optarg)
+ debugopt[*ctx.optarg++ & 0x7f]++;
+ break;
+ case 'I':
+ lappend(&incpaths, &nincpaths, ctx.optarg);
+ break;
+ default:
+ usage(argv[0]);
+ exit(0);
+ break;
+ }
+ }
+
+ lappend(&incpaths, &nincpaths, Instroot "/lib/myr");
+
+ if (ctx.nargs == 0) {
+ fprintf(stderr, "No input files given\n");
+ exit(1);
+ }
+ else if (ctx.nargs > 1)
+ outfile = NULL;
+
+ for (i = 0; i < ctx.nargs; i++) {
+ if (outfile)
+ localincpath = dirname(outfile);
+ else
+ localincpath = dirname(ctx.args[i]);
+ globls = mkstab(0);
+ tyinit(globls);
+ tokinit(ctx.args[i]);
+ file = mkfile(ctx.args[i]);
+ file->file.globls = globls;
+ yyparse();
+
+ /* before we do anything to the parse */
+ if (debugopt['T'])
+ dump(file, stdout);
+ infer();
+ if (hasmain())
+ geninit();
+ tagexports(file, 0);
+ /* after all type inference */
+ if (debugopt['t'])
+ dump(file, stdout);
+
+ if (writeasm) {
+ if (outfile != NULL) {
+ swapout(qsbuf, sizeof qsbuf, ".qs");
+ swapout(asbuf, sizeof asbuf, ".s");
+ } else {
+ swapsuffix(qsbuf, sizeof qsbuf, ctx.args[i], ".myr", ".qs");
+ swapsuffix(asbuf, sizeof asbuf, ctx.args[i], ".myr", ".s");
+ }
+ } else {
+ gentempfile(qsbuf, sizeof qsbuf, ctx.args[i], ".qs");
+ gentempfile(asbuf, sizeof asbuf, ctx.args[i], ".s");
+ }
+ genuse(ctx.args[i]);
+ gen(file, qsbuf);
+ assemble(qsbuf, asbuf, ctx.args[i]);
+
+ free(localincpath);
+ }
+
+ return 0;
+}
diff --git a/6q/qasm.h b/6q/qasm.h
new file mode 100644
index 0000000..c7fea8e
--- /dev/null
+++ b/6q/qasm.h
@@ -0,0 +1,141 @@
+#define Maxarg 4 /* maximum number of args an insn can have */
+#define Wordsz 4 /* the size of a "natural int" */
+#define Ptrsz 8 /* the size of a machine word (ie, pointer size) */
+#define Narg 2 /* the maximum number of args for 'normal' instructions */
+
+typedef struct Blob Blob;
+typedef struct Insn Insn;
+typedef struct Loc Loc;
+typedef struct Gen Gen;
+
+typedef enum {
+#define Insn(op) Q##op,
+#include "qbe.def"
+#undef Insn
+} Qop;
+
+typedef enum {
+ Bti8,
+ Bti16,
+ Bti32,
+ Bti64,
+ Btimin, /* byte-packed uint */
+ Btref,
+ Btbytes,
+ Btseq,
+ Btpad,
+} Blobtype;
+
+typedef enum {
+ Ldecl,
+ Ltemp,
+ Llabel,
+ Lconst,
+ Lblob,
+} Loctype;
+
+struct Loc {
+ char tag;
+ char kind;
+ union {
+ vlong dcl;
+ vlong tmp;
+ vlong cst;
+ char *lbl;
+ Blob *blob;
+ };
+};
+
+#define Zq ((Loc){.tag=0, .kind=0})
+
+struct Insn {
+ Qop op;
+ Loc dst;
+ Loc ret;
+ union {
+ Loc arg[Narg];
+ /* for func call */
+ struct {
+ Loc env;
+ Loc fn;
+ Loc *farg;
+ Type **fty;
+ size_t nfarg;
+ };
+ };
+};
+
+struct Blob {
+ Blobtype type;
+ size_t align;
+ char *lbl; /* may be null */
+ char isglobl;
+ char iscomdat;
+ union {
+ uint64_t npad;
+ uint64_t ival;
+ struct {
+ char *str;
+ char isextern;
+ size_t off;
+ } ref;
+ struct {
+ size_t len;
+ char *buf;
+ } bytes;
+ struct {
+ size_t nsub;
+ Blob **sub;
+ } seq;
+ };
+};
+
+struct Gen {
+ FILE *f;
+ Cfg *cfg;
+ char **typenames;
+ Htab *globls;
+ Blob **blobs;
+ size_t nblobs;
+
+ Type **vatype;
+ size_t nvatype;
+
+ Node **local;
+ size_t nlocal;
+ size_t nexttmp;
+
+ Type *rettype;
+ Node *retval;
+ Loc *arg;
+ size_t narg;
+ Loc retlbl;
+
+ Insn *insn;
+ size_t ninsn;
+ size_t insnsz;
+};
+
+void gen(Node *file, char *out);
+
+/* type info stuff */
+size_t tysize(Type *t);
+size_t tyalign(Type *t);
+size_t alignto(size_t sz, Type *t);
+size_t size(Node *n);
+ssize_t tyoffset(Type *ty, Node *memb);
+ssize_t offset(Node *aggr, Node *memb);
+
+/* blob stuff */
+Blob *mkblobpad(size_t sz);
+Blob *mkblobi(Blobtype type, uint64_t ival);
+Blob *mkblobbytes(char *buf, size_t len);
+Blob *mkblobseq(Blob **sub, size_t nsub);
+Blob *mkblobref(char *lbl, size_t off, int isextern);
+void blobfree(Blob *b);
+
+Blob *tydescblob(Type *t);
+size_t blobsz(Blob *b);
+size_t blobrec(Gen *g, Blob *b, Node *n);
+void genblob(Gen *g, Blob *b);
+char *tydescid(char *buf, size_t bufsz, Type *ty);
diff --git a/6q/qbe.def b/6q/qbe.def
new file mode 100644
index 0000000..d54a9b7
--- /dev/null
+++ b/6q/qbe.def
@@ -0,0 +1,110 @@
+Insn(add)
+Insn(sub)
+Insn(div)
+Insn(rem)
+Insn(udiv)
+Insn(urem)
+Insn(mul)
+Insn(and)
+Insn(or)
+Insn(xor)
+Insn(sar)
+Insn(shr)
+Insn(shl)
+
+Insn(ceql)
+Insn(cnel)
+Insn(cslel)
+Insn(culel)
+Insn(csltl)
+Insn(cultl)
+Insn(csgel)
+Insn(cugel)
+Insn(csgtl)
+Insn(cugtl)
+
+Insn(ceqw)
+Insn(cnew)
+Insn(cslew)
+Insn(culew)
+Insn(csltw)
+Insn(cultw)
+Insn(csgew)
+Insn(cugew)
+Insn(csgtw)
+Insn(cugtw)
+
+Insn(ceqs)
+Insn(cnes)
+Insn(cles)
+Insn(clts)
+Insn(cges)
+Insn(cgts)
+
+Insn(ceqd)
+Insn(cned)
+Insn(cled)
+Insn(cltd)
+Insn(cged)
+Insn(cgtd)
+
+Insn(storeb)
+Insn(storeh)
+Insn(storew)
+Insn(storel)
+Insn(stores)
+Insn(stored)
+Insn(loadsb) /* must match Oext and Tmp.width */
+Insn(loadub)
+Insn(loadsh)
+Insn(loaduh)
+Insn(loadsw)
+Insn(loaduw)
+
+/* ??? are these all the same? */
+Insn(loadb)
+Insn(loadh)
+Insn(loadw)
+Insn(loadl)
+Insn(loads)
+Insn(loadd)
+
+Insn(extsb)
+Insn(extub)
+Insn(extsh)
+Insn(extuh)
+Insn(extsw)
+Insn(extuw)
+Insn(exts)
+Insn(truncd)
+Insn(stosi)
+Insn(dtosi)
+Insn(swtof)
+Insn(sltof)
+Insn(cast)
+Insn(alloc1)
+Insn(alloc2)
+Insn(alloc4)
+Insn(alloc8)
+Insn(copy)
+Insn(label)
+
+Insn(call)
+
+Insn(ret)
+Insn(retw)
+Insn(retl)
+Insn(rets)
+Insn(retd)
+Insn(retc)
+Insn(jmp)
+Insn(jnz)
+Insn(jule)
+Insn(jult)
+Insn(jsle)
+Insn(jslt)
+Insn(jsgt)
+Insn(jsge)
+Insn(jugt)
+Insn(juge)
+Insn(jeq)
diff --git a/6q/typeinfo.c b/6q/typeinfo.c
new file mode 100644
index 0000000..52afc46
--- /dev/null
+++ b/6q/typeinfo.c
@@ -0,0 +1,432 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "parse.h"
+#include "mi.h"
+#include "qasm.h"
+#include "../config.h"
+
+#define Tdindirect 0x80
+
+Blob *
+tydescsub(Type *ty);
+
+size_t
+alignto(size_t sz, Type *t)
+{
+ return align(sz, tyalign(t));
+}
+
+size_t
+blobsz(Blob *b)
+{
+ size_t n;
+ size_t i;
+
+ switch (b->type) {
+ case Bti8: return 1; break;
+ case Bti16: return 2; break;
+ case Bti32: return 4; break;
+ case Bti64: return 8; break;
+ case Btref: return 8; break;
+ case Btbytes: return b->bytes.len; break;
+ case Btimin:
+ if (b->ival >= 1ULL << 56)
+ die("packed int too big");
+
+ for (i = 1; i < 8; i++)
+ if (b->ival < 1ULL << (7*i))
+ return i;
+ die("impossible blob size");
+ break;
+ case Btseq:
+ n = 0;
+ for (i = 0; i < b->seq.nsub; i++)
+ n += blobsz(b->seq.sub[i]);
+ return n;
+ break;
+ default:
+ die("unknown blob type");
+ }
+ return 0;
+}
+
+void
+namevec(Blob ***sub, size_t *nsub, Node *n)
+{
+ char *buf;
+ size_t len;
+
+ if (n->name.ns) {
+ len = strlen(n->name.name) + strlen(n->name.ns) + 1;
+ buf = xalloc(len + 1);
+ bprintf(buf, len + 1, "%s.%s", n->name.ns, n->name.name);
+ } else {
+ len = strlen(n->name.name);
+ buf = xalloc(len + 1);
+ bprintf(buf, len + 1, "%s", n->name.name);
+ }
+ lappend(sub, nsub, mkblobi(Btimin, len));
+ lappend(sub, nsub, mkblobbytes(buf, len));
+}
+
+static void
+structmemb(Blob ***sub, size_t *nsub, Node *sdecl)
+{
+ Blob *b;
+
+ namevec(sub, nsub, sdecl->decl.name);
+ b = tydescsub(sdecl->decl.type);
+ lappend(sub, nsub, b);
+}
+
+static void
+unionmemb(Blob ***sub, size_t *nsub, Ucon *ucon)
+{
+ namevec(sub, nsub, ucon->name);
+ if (ucon->etype) {
+ lappend(sub, nsub, tydescsub(ucon->etype));
+ } else {
+ lappend(sub, nsub, mkblobi(Btimin, 1));
+ lappend(sub, nsub, mkblobi(Bti8, Tybad));
+ }
+}
+
+static void
+encodetypeinfo(Blob ***sub, size_t *nsub, Type *t)
+{
+ lappend(sub, nsub, mkblobi(Btimin, tysize(t)));
+ lappend(sub, nsub, mkblobi(Btimin, tyalign(t)));
+}
+
+Blob *
+tydescsub(Type *ty)
+{
+ Blob **sub, *sz, *bt, *b;
+ size_t i, nsub;
+ char buf[512];
+ uint8_t tt;
+ Node *len;
+ int isextern;
+
+ sub = NULL;
+ nsub = 0;
+ /* names are pulled out of line */
+ tt = ty->type;
+ /* tyvars can get tagged, but aren't desired */
+ if (ty->type == Tyvar)
+ return NULL;
+
+ ty = tydedup(ty);
+ if (ty->type == Tyname)
+ tt |= Tdindirect;
+ sz = mkblobi(Btimin, 0);
+ bt = mkblobi(Bti8, tt);
+ lappend(&sub, &nsub, bt);
+ switch (ty->type) {
+ case Ntypes: case Tyvar: case Tybad: case Typaram:
+ case Tygeneric: case Tycode: case Tyunres:
+ die("invalid type in tydesc");
+ break;
+
+ /* atomic types -- nothing else to do */
+ case Tyvoid: case Tychar: case Tybool: case Tyint8:
+ case Tyint16: case Tyint: case Tyint32: case Tyint64:
+ case Tybyte: case Tyuint8: case Tyuint16:
+ case Tyuint: case Tyuint32: case Tyuint64:
+ case Tyflt32: case Tyflt64: case Tyvalist:
+ break;
+
+ case Typtr:
+ lappend(&sub, &nsub, tydescsub(ty->sub[0]));
+ break;
+ case Tyslice:
+ lappend(&sub, &nsub, tydescsub(ty->sub[0]));
+ break;
+ case Tyarray:
+ encodetypeinfo(&sub, &nsub, ty);
+ ty->asize = fold(ty->asize, 1);
+ len = ty->asize;
+ if (len) {
+ assert(len->type == Nexpr);
+ len = len->expr.args[0];
+ assert(len->type == Nlit && len->lit.littype == Lint);
+ lappend(&sub, &nsub, mkblobi(Btimin, len->lit.intval));
+ } else {
+ lappend(&sub, &nsub, mkblobi(Btimin, 0));
+ }
+
+ lappend(&sub, &nsub, tydescsub(ty->sub[0]));
+ break;
+ case Tyfunc:
+ lappend(&sub, &nsub, mkblobi(Btimin, ty->nsub));
+ for (i = 0; i < ty->nsub; i++)
+ lappend(&sub, &nsub, tydescsub(ty->sub[i]));
+ break;
+ case Tytuple:
+ encodetypeinfo(&sub, &nsub, ty);
+ lappend(&sub, &nsub, mkblobi(Btimin, ty->nsub));
+ for (i = 0; i < ty->nsub; i++)
+ lappend(&sub, &nsub, tydescsub(ty->sub[i]));
+ break;
+ case Tystruct:
+ encodetypeinfo(&sub, &nsub, ty);
+ lappend(&sub, &nsub, mkblobi(Btimin, ty->nmemb));
+ for (i = 0; i < ty->nmemb; i++)
+ structmemb(&sub, &nsub, ty->sdecls[i]);
+ break;
+ case Tyunion:
+ encodetypeinfo(&sub, &nsub, ty);
+ lappend(&sub, &nsub, mkblobi(Btimin, ty->nmemb));
+ for (i = 0; i < ty->nmemb; i++)
+ unionmemb(&sub, &nsub, ty->udecls[i]);
+ break;
+ case Tyname:
+ i = bprintf(buf, sizeof buf, "%s", Symprefix);
+ tydescid(buf + i, sizeof buf - i, ty);
+ isextern = ty->isimport || ty->vis != Visintern;
+ lappend(&sub, &nsub, mkblobref(buf, 0, isextern));
+ break;
+ }
+ b = mkblobseq(sub, nsub);
+ sz->ival = blobsz(b);
+ linsert(&b->seq.sub, &b->seq.nsub, 0, sz);
+ return b;
+}
+
+Blob *
+namedesc(Type *ty)
+{
+ Blob **sub;
+ size_t nsub;
+
+ sub = NULL;
+ nsub = 0;
+ lappend(&sub, &nsub, mkblobi(Bti8, Tyname));
+ namevec(&sub, &nsub, ty->name);
+ lappend(&sub, &nsub, tydescsub(ty->sub[0]));
+ return mkblobseq(sub, nsub);
+}
+
+Blob *
+tydescblob(Type *ty)
+{
+ char buf[512];
+ Blob *b, *sz, *sub;
+
+ if (ty->type == Tyname && hasparams(ty))
+ return NULL;
+
+ if (ty->type == Tyname) {
+ b = mkblobseq(NULL, 0);
+ sz = mkblobi(Btimin, 0);
+ sub = namedesc(ty);
+ sz->ival = blobsz(sub);
+ lappend(&b->seq.sub, &b->seq.nsub, sz);
+ lappend(&b->seq.sub, &b->seq.nsub, sub);
+ if (ty->vis != Visintern)
+ b->isglobl = 1;
+ } else {
+ b = tydescsub(ty);
+ }
+ tydescid(buf, sizeof buf, ty);
+ b->lbl = strdup(buf);
+ return b;
+}
+
+size_t
+tysize(Type *t)
+{
+ size_t sz;
+ size_t i;
+
+ sz = 0;
+ if (!t)
+ die("size of empty type => bailing.");
+ switch (t->type) {
+ case Tyvoid:
+ return 0;
+ case Tybool: case Tyint8:
+ case Tybyte: case Tyuint8:
+ return 1;
+ case Tyint16: case Tyuint16:
+ return 2;
+ case Tyint: case Tyint32:
+ case Tyuint: case Tyuint32:
+ case Tychar: /* utf32 */
+ return 4;
+
+ case Typtr:
+ case Tyvalist: /* ptr to first element of valist */
+ return Ptrsz;
+
+ case Tyint64:
+ case Tyuint64:
+ return 8;
+
+ /*end integer types*/
+ case Tyflt32:
+ return 4;
+ case Tyflt64:
+ return 8;
+
+ case Tycode:
+ return Ptrsz;
+ case Tyfunc:
+ return 2*Ptrsz;
+ case Tyslice:
+ return 2*Ptrsz; /* len; ptr */
+ case Tyname:
+ return tysize(t->sub[0]);
+ case Tyarray:
+ if (!t->asize)
+ return 0;
+ t->asize = fold(t->asize, 1);
+ assert(exprop(t->asize) == Olit);
+ return t->asize->expr.args[0]->lit.intval * tysize(t->sub[0]);
+ case Tytuple:
+ for (i = 0; i < t->nsub; i++) {
+ sz = alignto(sz, t->sub[i]);
+ sz += tysize(t->sub[i]);
+ }
+ sz = alignto(sz, t);
+ return sz;
+ break;
+ case Tystruct:
+ for (i = 0; i < t->nmemb; i++) {
+ sz = alignto(sz, decltype(t->sdecls[i]));
+ sz += size(t->sdecls[i]);
+ }
+ sz = alignto(sz, t);
+ return sz;
+ break;
+ case Tyunion:
+ sz = Wordsz;
+ for (i = 0; i < t->nmemb; i++)
+ if (t->udecls[i]->etype)
+ sz = max(sz, tysize(t->udecls[i]->etype) + Wordsz);
+ return align(sz, tyalign(t));
+ break;
+ case Tygeneric: case Tybad: case Tyvar:
+ case Typaram: case Tyunres: case Ntypes:
+ die("Type %s does not have size; why did it get down to here?", tystr(t));
+ break;
+ }
+ return -1;
+}
+
+size_t
+tyalign(Type *ty)
+{
+ size_t align, i;
+
+ align = 1;
+ ty = tybase(ty);
+ switch (ty->type) {
+ case Tyarray:
+ align = tyalign(ty->sub[0]);
+ break;
+ case Tytuple:
+ for (i = 0; i < ty->nsub; i++)
+ align = max(align, tyalign(ty->sub[0]));
+ break;
+ case Tyunion:
+ align = 4;
+ for (i = 0; i < ty->nmemb; i++)
+ if (ty->udecls[i]->etype)
+ align = max(align, tyalign(ty->udecls[i]->etype));
+ break;
+ case Tystruct:
+ for (i = 0; i < ty->nmemb; i++)
+ align = max(align, tyalign(decltype(ty->sdecls[i])));
+ break;
+ default:
+ align = max(align, tysize(ty));
+ }
+ return min(align, Ptrsz);
+}
+
+/* gets the byte offset of 'memb' within the aggregate type 'aggr' */
+ssize_t
+tyoffset(Type *ty, Node *memb)
+{
+ size_t i;
+ size_t off;
+
+ ty = tybase(ty);
+ if (ty->type == Typtr)
+ ty = tybase(ty->sub[0]);
+
+ assert(ty->type == Tystruct);
+ off = 0;
+ for (i = 0; i < ty->nmemb; i++) {
+ off = alignto(off, decltype(ty->sdecls[i]));
+ if (!strcmp(namestr(memb), declname(ty->sdecls[i])))
+ return off;
+ off += size(ty->sdecls[i]);
+ }
+ die("bad offset");
+ return 0;
+}
+
+size_t
+size(Node *n)
+{
+ Type *t;
+
+ if (n->type == Nexpr)
+ t = n->expr.type;
+ else
+ t = n->decl.type;
+ return tysize(t);
+}
+
+ssize_t
+offset(Node *aggr, Node *memb)
+{
+ return tyoffset(exprtype(aggr), memb);
+}
+
+char *
+tydescid(char *buf, size_t bufsz, Type *ty)
+{
+ char *sep, *ns;
+ char *p, *end;
+ size_t i;
+
+ sep = "";
+ ns = "";
+ p = buf;
+ end = buf + bufsz;
+ ty = tydedup(ty);
+ if (ty->type == Tyname) {
+ if (ty->name->name.ns) {
+ ns = ty->name->name.ns;
+ sep = "$";
+ }
+ if (ty->vis != Visintern || ty->isimport)
+ p += bprintf(p, end - p, "_tydesc$%s%s%s", ns, sep, ty->name->name.name, ty->tid);
+ else
+ p += bprintf(p, end - p, "_tydesc$%s%s%s$%d", ns, sep, ty->name->name.name, ty->tid);
+ for (i = 0; i < ty->narg; i++)
+ p += tyidfmt(p, end - p, ty->arg[i]);
+ } else {
+ if (file->file.globls->name) {
+ ns = file->file.globls->name;
+ sep = "$";
+ }
+ bprintf(buf, bufsz, "_tydesc%s%s$%d",sep, ns, ty->tid);
+ }
+ return buf;
+}
+
diff --git a/Makefile b/Makefile
index c48939c..b7c85f5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
SUB = parse \
mi \
util \
- 6 \
+ 6q \
muse \
rt \
diff --git a/boot6qm.sh b/boot6qm.sh
new file mode 100755
index 0000000..2885f12
--- /dev/null
+++ b/boot6qm.sh
@@ -0,0 +1,136 @@
+#!/bin/sh
+# This script is generated by genbootstrap.sh
+# to regenerate, run "make bootstrap"
+pwd=`pwd`
+echo cd $pwd/lib/sys && cd $pwd/lib/sys &&\
+echo as -g -o util.o util+posixy-x64.s && as -g -o util.o util+posixy-x64.s &&\
+echo $pwd/6q/6qm syserrno+freebsd.myr && $pwd/6q/6qm syserrno+freebsd.myr &&\
+echo $pwd/6q/6qm systypes.myr && $pwd/6q/6qm systypes.myr &&\
+echo $pwd/6q/6qm sys+freebsd-x64.myr && $pwd/6q/6qm sys+freebsd-x64.myr &&\
+echo as -g -o syscall.o syscall+freebsd-x64.s && as -g -o syscall.o syscall+freebsd-x64.s &&\
+echo $pwd/6q/6qm ifreq+freebsd.myr && $pwd/6q/6qm ifreq+freebsd.myr &&\
+echo $pwd/muse/muse -o libsys.use -p sys sys.use syserrno.use systypes.use ifreq.use && $pwd/muse/muse -o libsys.use -p sys sys.use syserrno.use systypes.use ifreq.use &&\
+echo ar -rcs libsys.a sys.o syscall.o syserrno.o util.o systypes.o ifreq.o && ar -rcs libsys.a sys.o syscall.o syserrno.o util.o systypes.o ifreq.o &&\
+echo cd $pwd/lib/std && cd $pwd/lib/std &&\
+echo $pwd/6q/6qm -I ../sys -I . types.myr && $pwd/6q/6qm -I ../sys -I . types.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . cstrconv.myr && $pwd/6q/6qm -I ../sys -I . cstrconv.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . errno.myr && $pwd/6q/6qm -I ../sys -I . errno.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . option.myr && $pwd/6q/6qm -I ../sys -I . option.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . result.myr && $pwd/6q/6qm -I ../sys -I . result.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . syswrap+posixy.myr && $pwd/6q/6qm -I ../sys -I . syswrap+posixy.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . die.myr && $pwd/6q/6qm -I ../sys -I . die.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . sleq.myr && $pwd/6q/6qm -I ../sys -I . sleq.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . hassuffix.myr && $pwd/6q/6qm -I ../sys -I . hassuffix.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . extremum.myr && $pwd/6q/6qm -I ../sys -I . extremum.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . memops.myr && $pwd/6q/6qm -I ../sys -I . memops.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . threadhooks.myr && $pwd/6q/6qm -I ../sys -I . threadhooks.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . units.myr && $pwd/6q/6qm -I ../sys -I . units.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . slfill.myr && $pwd/6q/6qm -I ../sys -I . slfill.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . backtrace+x64.myr && $pwd/6q/6qm -I ../sys -I . backtrace+x64.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . bytealloc.myr && $pwd/6q/6qm -I ../sys -I . bytealloc.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . alloc.myr && $pwd/6q/6qm -I ../sys -I . alloc.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . consts.myr && $pwd/6q/6qm -I ../sys -I . consts.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . chartype.myr && $pwd/6q/6qm -I ../sys -I . chartype.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . utf.myr && $pwd/6q/6qm -I ../sys -I . utf.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . cmp.myr && $pwd/6q/6qm -I ../sys -I . cmp.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . hasprefix.myr && $pwd/6q/6qm -I ../sys -I . hasprefix.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . slcp.myr && $pwd/6q/6qm -I ../sys -I . slcp.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . sldup.myr && $pwd/6q/6qm -I ../sys -I . sldup.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . slpush.myr && $pwd/6q/6qm -I ../sys -I . slpush.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . strfind.myr && $pwd/6q/6qm -I ../sys -I . strfind.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . striter.myr && $pwd/6q/6qm -I ../sys -I . striter.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . bigint.myr && $pwd/6q/6qm -I ../sys -I . bigint.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . fltbits.myr && $pwd/6q/6qm -I ../sys -I . fltbits.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . strbuf.myr && $pwd/6q/6qm -I ../sys -I . strbuf.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . fltfmt.myr && $pwd/6q/6qm -I ../sys -I . fltfmt.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . hashfuncs.myr && $pwd/6q/6qm -I ../sys -I . hashfuncs.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . htab.myr && $pwd/6q/6qm -I ../sys -I . htab.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . intparse.myr && $pwd/6q/6qm -I ../sys -I . intparse.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . introspect.myr && $pwd/6q/6qm -I ../sys -I . introspect.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . strstrip.myr && $pwd/6q/6qm -I ../sys -I . strstrip.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . strsplit.myr && $pwd/6q/6qm -I ../sys -I . strsplit.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . syswrap-ss+freebsd.myr && $pwd/6q/6qm -I ../sys -I . syswrap-ss+freebsd.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . varargs.myr && $pwd/6q/6qm -I ../sys -I . varargs.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . writeall.myr && $pwd/6q/6qm -I ../sys -I . writeall.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . fmt.myr && $pwd/6q/6qm -I ../sys -I . fmt.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . assert.myr && $pwd/6q/6qm -I ../sys -I . assert.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . mk.myr && $pwd/6q/6qm -I ../sys -I . mk.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . now.myr && $pwd/6q/6qm -I ../sys -I . now.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . putint.myr && $pwd/6q/6qm -I ../sys -I . putint.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . rand.myr && $pwd/6q/6qm -I ../sys -I . rand.myr &&\
+echo as -g -o getbp.o getbp+posixy-x64.s && as -g -o getbp.o getbp+posixy-x64.s &&\
+echo $pwd/6q/6qm -I ../sys -I . sljoin.myr && $pwd/6q/6qm -I ../sys -I . sljoin.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . readall.myr && $pwd/6q/6qm -I ../sys -I . readall.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . slurp.myr && $pwd/6q/6qm -I ../sys -I . slurp.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . dirname.myr && $pwd/6q/6qm -I ../sys -I . dirname.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . chomp.myr && $pwd/6q/6qm -I ../sys -I . chomp.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . fltparse.myr && $pwd/6q/6qm -I ../sys -I . fltparse.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . optparse.myr && $pwd/6q/6qm -I ../sys -I . optparse.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . dir+freebsd.myr && $pwd/6q/6qm -I ../sys -I . dir+freebsd.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . ipparse.myr && $pwd/6q/6qm -I ../sys -I . ipparse.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . endian.myr && $pwd/6q/6qm -I ../sys -I . endian.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . resolve+posixy.myr && $pwd/6q/6qm -I ../sys -I . resolve+posixy.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . dialparse+posixy.myr && $pwd/6q/6qm -I ../sys -I . dialparse+posixy.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . iterutil.myr && $pwd/6q/6qm -I ../sys -I . iterutil.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . env+posixy.myr && $pwd/6q/6qm -I ../sys -I . env+posixy.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . execvp.myr && $pwd/6q/6qm -I ../sys -I . execvp.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . slput.myr && $pwd/6q/6qm -I ../sys -I . slput.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . wait+posixy.myr && $pwd/6q/6qm -I ../sys -I . wait+posixy.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . spork.myr && $pwd/6q/6qm -I ../sys -I . spork.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . getint.myr && $pwd/6q/6qm -I ../sys -I . getint.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . blat.myr && $pwd/6q/6qm -I ../sys -I . blat.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . diriter.myr && $pwd/6q/6qm -I ../sys -I . diriter.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . clear.myr && $pwd/6q/6qm -I ../sys -I . clear.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . strjoin.myr && $pwd/6q/6qm -I ../sys -I . strjoin.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . pathjoin.myr && $pwd/6q/6qm -I ../sys -I . pathjoin.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . mktemp.myr && $pwd/6q/6qm -I ../sys -I . mktemp.myr &&\
+echo as -g -o memops-impl.o memops-impl+posixy-x64.s && as -g -o memops-impl.o memops-impl+posixy-x64.s &&\
+echo $pwd/6q/6qm -I ../sys -I . fndup.myr && $pwd/6q/6qm -I ../sys -I . fndup.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . mkpath.myr && $pwd/6q/6qm -I ../sys -I . mkpath.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . listen+posixy.myr && $pwd/6q/6qm -I ../sys -I . listen+posixy.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . slpop.myr && $pwd/6q/6qm -I ../sys -I . slpop.myr &&\
+echo as -g -o sjlj-impl.o sjlj-impl+posixy-x64.s && as -g -o sjlj-impl.o sjlj-impl+posixy-x64.s &&\
+echo $pwd/6q/6qm -I ../sys -I . bitset.myr && $pwd/6q/6qm -I ../sys -I . bitset.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . fmtfuncs.myr && $pwd/6q/6qm -I ../sys -I . fmtfuncs.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . netaddr.myr && $pwd/6q/6qm -I ../sys -I . netaddr.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . sleep.myr && $pwd/6q/6qm -I ../sys -I . sleep.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . try.myr && $pwd/6q/6qm -I ../sys -I . try.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . sort.myr && $pwd/6q/6qm -I ../sys -I . sort.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . search.myr && $pwd/6q/6qm -I ../sys -I . search.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . getcwd.myr && $pwd/6q/6qm -I ../sys -I . getcwd.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . swap.myr && $pwd/6q/6qm -I ../sys -I . swap.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . sjlj.myr && $pwd/6q/6qm -I ../sys -I . sjlj.myr &&\
+echo $pwd/6q/6qm -I ../sys -I . dial+posixy.myr && $pwd/6q/6qm -I ../sys -I . dial+posixy.myr &&\
+echo $pwd/muse/muse -o libstd.use -p std dial.use fmtfuncs.use fmt.use try.use pathjoin.use strjoin.use sljoin.use slpush.use strstrip.use htab.use now.use getcwd.use rand.use slurp.use varargs.use listen.use strbuf.use clear.use slput.use strsplit.use introspect.use mktemp.use alloc.use optparse.use memops.use bytealloc.use fltbits.use striter.use sldup.use fltfmt.use extremum.use option.use errno.use wait.use slcp.use writeall.use putint.use consts.use syswrap.use sleep.use readall.use sort.use dir.use blat.use diriter.use sjlj.use fltparse.use backtrace.use mk.use swap.use hassuffix.use execvp.use netaddr.use ipparse.use types.use slpop.use strfind.use utf.use dialparse.use cstrconv.use search.use die.use units.use result.use bitset.use env.use resolve.use intparse.use hasprefix.use mkpath.use getint.use dirname.use sleq.use endian.use iterutil.use spork.use assert.use cmp.use syswrap-ss.use chartype.use bigint.use hashfuncs.use slfill.use threadhooks.use fndup.use chomp.use && $pwd/muse/muse -o libstd.use -p std dial.use fmtfuncs.use fmt.use try.use pathjoin.use strjoin.use sljoin.use slpush.use strstrip.use htab.use now.use getcwd.use rand.use slurp.use varargs.use listen.use strbuf.use clear.use slput.use strsplit.use introspect.use mktemp.use alloc.use optparse.use memops.use bytealloc.use fltbits.use striter.use sldup.use fltfmt.use extremum.use option.use errno.use wait.use slcp.use writeall.use putint.use consts.use syswrap.use sleep.use readall.use sort.use dir.use blat.use diriter.use sjlj.use fltparse.use backtrace.use mk.use swap.use hassuffix.use execvp.use netaddr.use ipparse.use types.use slpop.use strfind.use utf.use dialparse.use cstrconv.use search.use die.use units.use result.use bitset.use env.use resolve.use intparse.use hasprefix.use mkpath.use getint.use dirname.use sleq.use endian.use iterutil.use spork.use assert.use cmp.use syswrap-ss.use chartype.use bigint.use hashfuncs.use slfill.use threadhooks.use fndup.use chomp.use &&\
+echo ar -rcs libstd.a dial.o fmtfuncs.o fmt.o try.o pathjoin.o strjoin.o memops-impl.o sljoin.o slpush.o strstrip.o htab.o now.o getbp.o getcwd.o rand.o slurp.o varargs.o listen.o strbuf.o clear.o slput.o strsplit.o introspect.o mktemp.o alloc.o optparse.o memops.o bytealloc.o fltbits.o striter.o sldup.o fltfmt.o extremum.o option.o errno.o wait.o slcp.o writeall.o putint.o consts.o syswrap.o sleep.o readall.o sort.o dir.o blat.o diriter.o sjlj.o fltparse.o backtrace.o mk.o swap.o hassuffix.o execvp.o netaddr.o ipparse.o types.o slpop.o strfind.o utf.o dialparse.o cstrconv.o search.o die.o units.o result.o bitset.o env.o resolve.o intparse.o hasprefix.o mkpath.o getint.o dirname.o sleq.o endian.o iterutil.o spork.o assert.o cmp.o syswrap-ss.o sjlj-impl.o chartype.o bigint.o hashfuncs.o slfill.o threadhooks.o fndup.o chomp.o && ar -rcs libstd.a dial.o fmtfuncs.o fmt.o try.o pathjoin.o strjoin.o memops-impl.o sljoin.o slpush.o strstrip.o htab.o now.o getbp.o getcwd.o rand.o slurp.o varargs.o listen.o strbuf.o clear.o slput.o strsplit.o introspect.o mktemp.o alloc.o optparse.o memops.o bytealloc.o fltbits.o striter.o sldup.o fltfmt.o extremum.o option.o errno.o wait.o slcp.o writeall.o putint.o consts.o syswrap.o sleep.o readall.o sort.o dir.o blat.o diriter.o sjlj.o fltparse.o backtrace.o mk.o swap.o hassuffix.o execvp.o netaddr.o ipparse.o types.o slpop.o strfind.o utf.o dialparse.o cstrconv.o search.o die.o units.o result.o bitset.o env.o resolve.o intparse.o hasprefix.o mkpath.o getint.o dirname.o sleq.o endian.o iterutil.o spork.o assert.o cmp.o syswrap-ss.o sjlj-impl.o chartype.o bigint.o hashfuncs.o slfill.o threadhooks.o fndup.o chomp.o &&\
+echo cd $pwd/lib/regex && cd $pwd/lib/regex &&\
+echo $pwd/6q/6qm -I ../std -I ../sys types.myr && $pwd/6q/6qm -I ../std -I ../sys types.myr &&\
+echo $pwd/6q/6qm -I ../std -I ../sys interp.myr && $pwd/6q/6qm -I ../std -I ../sys interp.myr &&\
+echo $pwd/6q/6qm -I ../std -I ../sys ranges.myr && $pwd/6q/6qm -I ../std -I ../sys ranges.myr &&\
+echo $pwd/6q/6qm -I ../std -I ../sys compile.myr && $pwd/6q/6qm -I ../std -I ../sys compile.myr &&\
+echo $pwd/muse/muse -o libregex.use -p regex interp.use types.use compile.use ranges.use && $pwd/muse/muse -o libregex.use -p regex interp.use types.use compile.use ranges.use &&\
+echo ar -rcs libregex.a interp.o types.o compile.o ranges.o && ar -rcs libregex.a interp.o types.o compile.o ranges.o &&\
+echo cd $pwd/lib/bio && cd $pwd/lib/bio &&\
+echo $pwd/6q/6qm -I ../sys -I ../std bio.myr && $pwd/6q/6qm -I ../sys -I ../std bio.myr &&\
+echo $pwd/6q/6qm -I ../sys -I ../std puti.myr && $pwd/6q/6qm -I ../sys -I ../std puti.myr &&\
+echo $pwd/6q/6qm -I ../sys -I ../std iter.myr && $pwd/6q/6qm -I ../sys -I ../std iter.myr &&\
+echo $pwd/6q/6qm -I ../sys -I ../std mem.myr && $pwd/6q/6qm -I ../sys -I ../std mem.myr &&\
+echo $pwd/6q/6qm -I ../sys -I ../std geti.myr && $pwd/6q/6qm -I ../sys -I ../std geti.myr &&\
+echo $pwd/muse/muse -o libbio.use -p bio puti.use bio.use mem.use geti.use iter.use && $pwd/muse/muse -o libbio.use -p bio puti.use bio.use mem.use geti.use iter.use &&\
+echo ar -rcs libbio.a puti.o bio.o mem.o geti.o iter.o && ar -rcs libbio.a puti.o bio.o mem.o geti.o iter.o &&\
+echo cd $pwd/mbld && cd $pwd/mbld &&\
+echo $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys config.myr && $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys config.myr &&\
+echo $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys opts.myr && $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys opts.myr &&\
+echo $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys types.myr && $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys types.myr &&\
+echo $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys util.myr && $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys util.myr &&\
+echo $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys deps.myr && $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys deps.myr &&\
+echo $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys syssel.myr && $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys syssel.myr &&\
+echo $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys parse.myr && $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys parse.myr &&\
+echo $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys build.myr && $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys build.myr &&\
+echo $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys install.myr && $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys install.myr &&\
+echo $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys subtest.myr && $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys subtest.myr &&\
+echo $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys clean.myr && $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys clean.myr &&\
+echo $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys test.myr && $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys test.myr &&\
+echo $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys main.myr && $pwd/6q/6qm -I ../lib/regex -I ../lib/bio -I ../lib/std -I ../lib/sys main.myr &&\
+echo ld -o mbld $pwd/rt/_myrrt.o clean.o config.o deps.o types.o syssel.o util.o subtest.o parse.o main.o build.o opts.o install.o test.o -L../lib/regex -L../lib/bio -L../lib/std -L../lib/sys -lregex -lbio -lstd -lsys && ld -o mbld $pwd/rt/_myrrt.o clean.o config.o deps.o types.o syssel.o util.o subtest.o parse.o main.o build.o opts.o install.o test.o -L../lib/regex -L../lib/bio -L../lib/std -L../lib/sys -lregex -lbio -lstd -lsys &&\
+true
diff --git a/lib/std/bytealloc.myr b/lib/std/bytealloc.myr
index bb1be41..9b48acc 100644
--- a/lib/std/bytealloc.myr
+++ b/lib/std/bytealloc.myr
@@ -14,11 +14,6 @@ pkg std =
const startalloctrace : (f : byte[:] -> void)
const endalloctrace : (-> void)
- /* public for testing */
- pkglocal const zbytealloc : (sz:size -> byte#)
- const bytealloc : (sz:size -> byte#)
- const bytefree : (m:byte#, sz:size -> void)
-
/* null pointers. only used internally. */
pkglocal const Zsliceptr = (0 : byte#)
pkglocal const Align = 16 /* minimum allocation alignment */
@@ -26,6 +21,9 @@ pkg std =
pkglocal const align : (m : std.size, align : std.size -> std.size)
pkglocal const allocsz : (sz : std.size -> std.size)
+ pkglocal const bytealloc : (sz:size -> byte#)
+ pkglocal const zbytealloc : (sz:size -> byte#)
+ pkglocal const bytefree : (m:byte#, sz:size -> void)
;;
const Zslab = (0 : slab#)
diff --git a/mi/flatten.c b/mi/flatten.c
index 9ef2c70..d449806 100644
--- a/mi/flatten.c
+++ b/mi/flatten.c
@@ -50,6 +50,8 @@ struct Flattenctx {
/* location handling */
Htab *globls;
+ Node **locals;
+ size_t nlocals;
size_t stksz;
};
@@ -112,12 +114,13 @@ islbl(Node *n)
}
static Node *
-temp(Flattenctx *flatten, Node *e)
+temp(Flattenctx *fc, Node *e)
{
Node *t, *dcl;
assert(e->type == Nexpr);
t = gentemp(e->loc, e->expr.type, &dcl);
+ lappend(&fc->locals, &fc->nlocals, dcl);
return t;
}
@@ -833,6 +836,7 @@ flattenidxiter(Flattenctx *s, Node *n)
seq = rval(s, n->iterstmt.seq);
idx = gentemp(n->loc, idxtype, &dcl);
+ lappend(&s->locals, &s->nlocals, dcl);
/* setup */
append(s, asn(idx, zero));
@@ -887,7 +891,7 @@ flattentraititer(Flattenctx *s, Node *n)
Loop l;
Node *lbody, *lclean, *lstep, *lmatch, *lend;
Node *done, *val, *iter, *valptr, *iterptr;
- Node *func, *call, *seq;
+ Node *func, *call, *dcl, *seq;
Trait *tr;
val = temp(s, n->iterstmt.elt);
@@ -929,7 +933,8 @@ flattentraititer(Flattenctx *s, Node *n)
/* call iterator step */
func = traitfn(n->loc, tr, "__iternext__", exprtype(iter));
call = mkexpr(n->loc, Ocall, func, iterptr, valptr, NULL);
- done = gentemp(n->loc, mktype(n->loc, Tybool), NULL);
+ done = gentemp(n->loc, mktype(n->loc, Tybool), &dcl);
+ lappend(&s->locals, &s->nlocals, dcl);
call->expr.type = exprtype(done);
append(s, asn(done, call));
cjmp(s, done, lmatch, lend);
@@ -1005,6 +1010,7 @@ flatten(Flattenctx *fc, Node *n)
case Nexpr: flattenexpr(fc, n); break;
case Ndecl:
append(fc, n);
+ lappend(&fc->locals, &fc->nlocals, n);
r = mkexpr(n->loc, Ovar, n->decl.name, NULL);
if (n->decl.init) {
t = rval(fc, n->decl.init);
@@ -1024,7 +1030,7 @@ flatten(Flattenctx *fc, Node *n)
}
static Node *
-flatteninit(Node *dcl)
+flatteninit(Node *dcl, Node ***locals, size_t *nlocals)
{
Flattenctx fc = {0,};
Node *lit, *fn, *blk, *body;
@@ -1039,6 +1045,11 @@ flatteninit(Node *dcl)
blk->block.nstmts = fc.nstmts;
fn->func.body = blk;
+ if (locals) {
+ *locals = fc.locals;
+ *nlocals = fc.nlocals;
+ }
+
return dcl;
}
@@ -1052,18 +1063,16 @@ ismain(Node *n)
}
Node *
-flattenfn(Node *dcl)
+flattenfn(Node *dcl, Node ***locals, size_t *nlocals)
{
- if (ismain(dcl))
+ if (ismain(dcl) && dcl->decl.vis == Visintern)
dcl->decl.vis = Vishidden;
if (dcl->decl.isextern || dcl->decl.isgeneric)
return dcl;
if (isconstfn(dcl)) {
- dcl = flatteninit(dcl);
- //lappend(fn, nfn, f);
+ dcl = flatteninit(dcl, locals, nlocals);
}
- //lappend(fn, nfn, f);
return dcl;
}
diff --git a/mi/mi.h b/mi/mi.h
index d9920e7..1807558 100644
--- a/mi/mi.h
+++ b/mi/mi.h
@@ -52,5 +52,5 @@ void genmatch(Node *m, Node *val, Node ***out, size_t *nout);
void genonematch(Node *pat, Node *val, Node *iftrue, Node *iffalse, Node ***out, size_t *nout, Node ***cap, size_t *ncap);
/* tree flattening */
-Node *flattenfn(Node *dcl);
+Node *flattenfn(Node *dcl, Node ***locals, size_t *nlocals);
int isconstfn(Node *n);
diff --git a/mk/c.mk b/mk/c.mk
index 25167bc..32184c6 100644
--- a/mk/c.mk
+++ b/mk/c.mk
@@ -1,8 +1,5 @@
.DEFAULT_GOAL=all
-_DEPS=$(addprefix .deps/, $(OBJ:.o=.d))
-
-_PCHDRS=$(shell [ -z "$(PCPKGS)" ] || pkg-config --cflags $(PCPKGS))
-_PCLIBS=$(shell [ -z "$(PCPKGS)" ] ||pkg-config --libs $(PCPKGS))
+_DEPS != echo $(OBJ) | sed 's@\(.*\).o@.deps/.d@g'
_LIBSRCHPATHS=$(addprefix -L, $(dir $(DEPS)))
_LIBINCPATHS=$(addprefix -I, $(dir $(DEPS))) $(_PCHDRS)
@@ -119,12 +116,12 @@ uninstall: subdirs-uninstall $(EXTRAUNINSTALL)
%.o: %.c $(GENHDR) .deps/stamp
$(CC) -c $(CFLAGS) $(_LIBINCPATHS) $<
-%.o: %.cpp $(GENHDR) .deps/stamp
- $(CXX) -c $(CFLAGS) $(_LIBINCPATHS) $<
-
-%.o: %.cc $(GENHDR) .deps/stamp
- $(CXX) -c $(CFLAGS) $(_LIBINCPATHS) $<
-
+#%.o: %.cpp $(GENHDR) .deps/stamp
+# $(CXX) -c $(CFLAGS) $(_LIBINCPATHS) $<
+#
+#%.o: %.cc $(GENHDR) .deps/stamp
+# $(CXX) -c $(CFLAGS) $(_LIBINCPATHS) $<
+#
.deps/stamp:
mkdir -p .deps && touch .deps/stamp
diff --git a/parse/node.c b/parse/node.c
index 6e9a8ce..d32d4ab 100644
--- a/parse/node.c
+++ b/parse/node.c
@@ -296,7 +296,7 @@ genlbl(Srcloc loc)
{
char buf[128];
- genlblstr(buf, 128, "");
+ genlblstr(buf, sizeof buf, "");
return mklbl(loc, buf);
}
diff --git a/parse/ops.def b/parse/ops.def
index dd9447a..49cd22d 100644
--- a/parse/ops.def
+++ b/parse/ops.def
@@ -57,20 +57,20 @@ O(Ostruct, 1, OTmisc, NULL)
O(Oarr, 1, OTmisc, NULL)
/* all below this point are backend-only */
-O(Odead, 0, OTmisc, "DEAD") /* dead code */
-O(Oundef, 0, OTmisc, "UNDEF") /* undefined var */
-O(Odef, 0, OTmisc, "DEF") /* defined var */
-O(Ocjmp, 1, OTmisc, "CJMP") /* conditional jump */
+O(Odead, 0, OTmisc, "DEAD") /* dead code */
+O(Oundef, 0, OTmisc, "UNDEF") /* undefined var */
+O(Odef, 0, OTmisc, "DEF") /* defined var */
+O(Ocjmp, 1, OTmisc, "CJMP") /* conditional jump */
O(Ovjmp, 1, OTmisc, "VJMP") /* variable arg list jump */
-O(Oset, 1, OTbin, "=") /* store to var */
+O(Oset, 1, OTbin, "=") /* store to var */
O(Osllen, 1, OTpre, "SLLEN") /* size of slice */
O(Oslbase, 1, OTpre, "SLBASE") /* base of sice */
-O(Outag, 1, OTpre, "UTAG") /* tag of union */
-O(Oudata, 1, OTpre, "UDATA") /* pointer to contents of union */
-O(Otupget, 1, OTpre, "TUPGET") /* pointer to contents of union */
-O(Oblit, 1, OTbin, "BLIT") /* blit memory */
-O(Oclear, 1, OTpre, "CLEAR") /* zero */
-O(Ocallind, 1, OTpre, "CALL") /* call with environment */
+O(Outag, 1, OTpre, "UTAG") /* tag of union */
+O(Oudata, 1, OTpre, "UDATA") /* pointer to contents of union */
+O(Otupget, 1, OTpre, "TUPGET") /* pointer to contents of union */
+O(Oblit, 1, OTbin, "BLIT") /* blit memory */
+O(Oclear, 1, OTpre, "CLEAR") /* zero */
+O(Ocallind, 1, OTpre, "CALL") /* call with environment */
/* integer conversions */
O(Otrunc, 1, OTmisc, NULL) /* truncating cast */
diff --git a/parse/parse.h b/parse/parse.h
index 07c0e03..9c6a658 100644
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -465,6 +465,7 @@ int istysigned(Type *t);
int istyunsigned(Type *t);
int istyfloat(Type *t);
int istyprimitive(Type *t);
+int istyconcrete(Type *t);
int hasparams(Type *t);
/* type manipulation */
@@ -536,7 +537,7 @@ Type *substget(Tysubst *subst, Type *from);
Node *specializedcl(Node *n, Type *param, Type *to, Node **name);
Type *tyspecialize(Type *t, Tysubst *tymap, Htab *delayed, Htab *tybase);
Node *genericname(Node *n, Type *param, Type *t);
-void geninit(Node *file);
+void geninit(void);
/* usefiles */
int loaduse(char *path, FILE *f, Stab *into, Vis vis);
diff --git a/parse/specialize.c b/parse/specialize.c
index c5d4a59..88a47ed 100644
--- a/parse/specialize.c
+++ b/parse/specialize.c
@@ -603,7 +603,7 @@ callinit(Node *block, Node *init, Type *tyvoid, Type *tyvoidfn)
}
void
-geninit(Node *file)
+geninit()
{
Node *name, *decl, *func, *block, *init;
Type *tyvoid, *tyvoidfn;
diff --git a/parse/type.c b/parse/type.c
index c31fbbe..ddd2cc5 100644
--- a/parse/type.c
+++ b/parse/type.c
@@ -387,7 +387,7 @@ istyprimitive(Type *t) { return istysigned(t) || istyunsigned(t) || istyfloat(t)
* parameers at all (ie, if it generic).
*/
int
-hasparamsrec(Type *t, Bitset *visited)
+hasparamsrec(Type *t, Bitset *visited, int chkconcrete)
{
size_t i;
@@ -395,31 +395,34 @@ hasparamsrec(Type *t, Bitset *visited)
return 0;
bsput(visited, t->tid);
switch (t->type) {
+ case Tyvar: return chkconcrete;
case Typaram: return 1;
case Tygeneric: return 1;
case Tyname:
for (i = 0; i < t->narg; i++)
- if (hasparamsrec(t->arg[i], visited))
+ if (hasparamsrec(t->arg[i], visited, chkconcrete))
return 1;
- return hasparamsrec(t->sub[0], visited);
+ return hasparamsrec(t->sub[0], visited, chkconcrete);
case Tyunres:
+ if (chkconcrete)
+ return 0;
for (i = 0; i < t->narg; i++)
- if (hasparamsrec(t->arg[i], visited))
+ if (hasparamsrec(t->arg[i], visited, chkconcrete))
return 1;
break;
case Tystruct:
for (i = 0; i < t->nmemb; i++)
- if (hasparamsrec(t->sdecls[i]->decl.type, visited))
+ if (hasparamsrec(t->sdecls[i]->decl.type, visited, chkconcrete))
return 1;
break;
case Tyunion:
for (i = 0; i < t->nmemb; i++)
- if (t->udecls[i]->etype && hasparamsrec(t->udecls[i]->etype, visited))
+ if (t->udecls[i]->etype && hasparamsrec(t->udecls[i]->etype, visited, chkconcrete))
return 1;
break;
default:
for (i = 0; i < t->nsub; i++)
- if (hasparamsrec(t->sub[i], visited))
+ if (hasparamsrec(t->sub[i], visited, chkconcrete))
return 1;
break;
}
@@ -427,6 +430,20 @@ hasparamsrec(Type *t, Bitset *visited)
}
int
+istyconcrete(Type *t)
+{
+ Bitset *s;
+ int r;
+
+ if (t->hasparams)
+ return 0;
+ s = mkbs();
+ r = hasparamsrec(t, s, 1);
+ bsfree(s);
+ return !r;
+}
+
+int
hasparams(Type *t)
{
Bitset *visited;
@@ -434,11 +451,10 @@ hasparams(Type *t)
if (t->hasparams)
return 1;
visited = mkbs();
- t->hasparams = hasparamsrec(t, visited);
+ t->hasparams = hasparamsrec(t, visited, 0);
bsfree(visited);
return t->hasparams;
}
-
Type *
tybase(Type *t)
{
diff --git a/parse/types.def b/parse/types.def
index c19e7d1..d2b4038 100644
--- a/parse/types.def
+++ b/parse/types.def
@@ -26,7 +26,7 @@ Ty(Tyuint64, "uint64", 0)
Ty(Tyflt32, "flt32", 0)
Ty(Tyflt64, "flt64", 0)
/* end primitive types */
-Ty(Tyvalist, NULL, 0)
+Ty(Tyvalist, NULL, 1)
/* end atomic types */
Ty(Typtr, NULL, 0)
diff --git a/util/pack.c b/util/pack.c
index 6457ba0..e386035 100644
--- a/util/pack.c
+++ b/util/pack.c
@@ -219,6 +219,24 @@ bprintf(char *buf, size_t sz, char *fmt, ...)
return n;
}
+char *
+strfmt(char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ size_t n;
+
+ va_start(ap, fmt);
+ n = vsnprintf(NULL, 0, fmt, ap);
+ buf = xalloc(n + 1);
+ va_end(ap);
+
+ va_start(ap, fmt);
+ vsnprintf(buf, n + 1, fmt, ap);
+ va_end(ap);
+ return buf;
+}
+
void
wrbool(FILE *fd, int val)
{
diff --git a/util/util.h b/util/util.h
index be09dfc..5f4d9af 100644
--- a/util/util.h
+++ b/util/util.h
@@ -125,6 +125,7 @@ void die(char *msg, ...) FATAL;
char *strdupn(char *s, size_t len);
char *xstrdup(char *s);
char *strjoin(char *u, char *v);
+char *strfmt(char *fmt, ...);
void *memdup(void *mem, size_t len);
size_t bprintf(char *buf, size_t len, char *fmt, ...);