summaryrefslogtreecommitdiff
path: root/6/blob.c
diff options
context:
space:
mode:
authorOri Bernstein <ori@eigenstate.org>2015-06-27 13:38:48 -0700
committerOri Bernstein <ori@eigenstate.org>2015-06-27 13:42:46 -0700
commita16c4e637079bb3d7f1cb93ae9b2348d710c003f (patch)
tree838d8df86ac165e931d62fa295c75d168b1f75cc /6/blob.c
parentfa8e0920764f9f298d6b6ac9471c862aec024e01 (diff)
downloadmc-a16c4e637079bb3d7f1cb93ae9b2348d710c003f.tar.gz
Factor out blob generation.
The logic for our type layout is common between platforms.
Diffstat (limited to '6/blob.c')
-rw-r--r--6/blob.c272
1 files changed, 272 insertions, 0 deletions
diff --git a/6/blob.c b/6/blob.c
new file mode 100644
index 0000000..b9240d7
--- /dev/null
+++ b/6/blob.c
@@ -0,0 +1,272 @@
+#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 "parse.h"
+#include "mi.h"
+#include "asm.h"
+#include "../config.h"
+
+static size_t blobrec(Blob *b, Htab *globls, Htab *strtab, Node *n);
+
+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;
+
+ 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;
+}
+
+void b(Blob *b, Blob *n)
+{
+ lappend(&b->seq.sub, &b->seq.nsub, n);
+}
+
+static size_t blobpad(Blob *seq, size_t sz)
+{
+ b(seq, mkblobpad(sz));
+ return sz;
+}
+
+static size_t bloblit(Blob *seq, Htab *strtab, Node *v, Type *ty)
+{
+ char buf[128];
+ char *lbl;
+ size_t sz;
+ Blobtype intsz[] = {
+ [1] = Bti8,
+ [2] = Bti16,
+ [4] = Bti32,
+ [8] = Bti64
+ };
+ union {
+ float fv;
+ double dv;
+ uint64_t qv;
+ uint32_t lv;
+ } u;
+
+ assert(v->type == Nlit);
+ sz = tysize(ty);
+ switch (v->lit.littype) {
+ 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:
+ 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));
+ }
+ b(seq, mkblobref(lbl, 0, 0));
+ b(seq, mkblobi(Bti64, v->lit.strval.len));
+ break;
+ case Lfunc:
+ die("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(Blob *seq, Htab *globls, Htab *strtab, Node *n)
+{
+ Node *base, *lo, *hi;
+ ssize_t loval, hival, sz;
+ 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 */
+ if (exprop(base) != Ovar || !base->expr.isconst)
+ fatal(base, "slice base is not a constant value");
+ loval = getintlit(lo, "lower bound in slice is not constant literal");
+ hival = getintlit(hi, "upper bound in slice is not constant literal");
+ sz = tysize(tybase(exprtype(base))->sub[0]);
+
+ lbl = htget(globls, base);
+ b(seq, mkblobref(lbl, loval*sz, 0));
+ 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(Blob *seq, Htab *globls, Htab *strtab, 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(seq, globls, strtab, m);
+ else
+ sz += blobpad(seq, size(dcl[i]));
+ }
+ end = alignto(sz, t);
+ sz += blobpad(seq, end - sz);
+ return sz;
+}
+
+static size_t blobucon(Blob *seq, Htab *globls, Htab *strtab, Node *n)
+{
+ size_t sz;
+ Ucon *uc;
+
+ sz = 4;
+ uc = finducon(exprtype(n), n->expr.args[0]);
+ b(seq, mkblobi(Bti32, uc->id));
+ if (n->expr.nargs > 1)
+ sz += blobrec(seq, globls, strtab, n->expr.args[1]);
+ sz += blobpad(seq, size(n) - sz);
+ return sz;
+}
+
+
+static size_t blobrec(Blob *b, Htab *globls, Htab *strtab, Node *n)
+{
+ size_t i, sz;
+
+ switch(exprop(n)) {
+ case Oucon: sz = blobucon(b, globls, strtab, n); break;
+ case Oslice: sz = blobslice(b, globls, strtab, n); break;
+ case Ostruct: sz = blobstruct(b, globls, strtab, n); break;
+ case Olit: sz = bloblit(b, strtab, n->expr.args[0], exprtype(n)); break;
+ case Otup:
+ case Oarr:
+ sz = 0;
+ for (i = 0; i < n->expr.nargs; i++)
+ sz += blobrec(b, globls, strtab, n->expr.args[i]);
+ break;
+ default:
+ dump(n, stdout);
+ die("Nonliteral initializer for global");
+ break;
+ }
+ return sz;
+}
+
+Blob *litblob(Htab *globls, Htab *strtab, Node *n)
+{
+ Blob *b;
+
+ b = mkblobseq(NULL, 0);
+ blobrec(b, globls, strtab, n);
+ return b;
+}