shithub: mc

Download patch

ref: ac3d02cdfbafe7b887cbd8738d3df9b17c5c82c9
parent: 1520007d5fd0238f7ea3bf7aa7269043976bf3d6
author: Ori Bernstein <ori@eigenstate.org>
date: Mon May 18 06:26:33 EDT 2015

Improve type generation code.

    This should be simpler to port to plan 9, and the data
    should be more compact.

--- a/6/asm.h
+++ b/6/asm.h
@@ -12,6 +12,7 @@
 typedef struct Blob Blob;
 typedef struct Isel Isel;
 typedef struct Asmbb Asmbb;
+typedef struct Blob Blob;
 
 typedef enum {
 #define Insn(val, gasfmt, p9fmt, use, def) val,
@@ -59,6 +60,35 @@
     Plan9,
 } Asmsyntax;
 
+typedef enum {
+    Bti8,
+    Bti16,
+    Bti32,
+    Bti64,
+    Btimin,     /* byte-packed uint */
+    Btref,
+    Btbytes,
+    Btseq,
+} Blobtype;
+
+struct Blob {
+    Blobtype type;
+    char *lbl;  /* may be null */
+    char isglobl;
+    union {
+        uint64_t ival;
+        char *ref;
+        struct {
+            size_t len;
+            char *buf;
+        } bytes;
+        struct {
+            size_t nsub;
+            Blob **sub;
+        } seq;
+    };
+};
+
 /* a register, label, or memory location */
 struct Loc {
     Loctype type; /* the type of loc */
@@ -205,6 +235,7 @@
 void gen(Node *file, char *out);
 void gengas(Node *file, char *out);
 void genp9(Node *file, char *out);
+Blob *tydescblob(Type *t);
 
 /* location generation */
 extern size_t maxregid;
@@ -237,7 +268,6 @@
 /* register allocation */
 void regalloc(Isel *s);
 Rclass rclass(Loc *l);
-
 
 /* useful functions */
 size_t tysize(Type *t);
--- a/6/gengas.c
+++ b/6/gengas.c
@@ -40,7 +40,6 @@
 
 static size_t writeblob(FILE *fd, Htab *globls, Htab *strtab, Node *blob);
 static void locprint(FILE *fd, Loc *l, char spec);
-static void gentydesc(FILE *fd, Type *ty);
 
 static void fillglobls(Stab *st, Htab *globls)
 {
@@ -490,131 +489,73 @@
     writeasm(fd, &is, fn);
 }
 
-void gennamevec(FILE *fd, Node *n)
+static void encodemin(FILE *fd, uint64_t val)
 {
-    if (n->name.ns) {
-        fprintf(fd, "\t.quad %zd\n", strlen(n->name.name) + strlen(n->name.ns) + 1);
-        fprintf(fd, "\t.ascii \"%s.%s\"\n", n->name.ns, n->name.name);
-    } else {
-        fprintf(fd, "\t.quad %zd\n", strlen(n->name.name));
-        fprintf(fd, "\t.ascii \"%s\"\n", n->name.name);
+    size_t i, shift;
+    uint8_t b;
+
+    for (i = 1; i < 8; i++)
+        if (val < 1ULL << (7*i))
+            break;
+    shift = 8 - i + 1;
+    b = ~0 << shift;
+    b |= val & ((1 << shift) - 1);
+    fprintf(fd, "\t.byte %u\n", b);
+    val >>= shift;
+    while (val != 0) {
+        fprintf(fd, "\t.byte %u\n", (uint)val & 0xff);
+        val >>= 8;
     }
 }
 
-static void genstructmemb(FILE *fd, Node *sdecl)
+static void gentyblob(FILE *fd, Blob *b)
 {
-    gennamevec(fd, sdecl->decl.name);
-    gentydesc(fd, sdecl->decl.type);
-}
-
-static void genunionmemb(FILE *fd, Ucon *ucon)
-{
-    gennamevec(fd, ucon->name);
-    if (ucon->etype)
-        gentydesc(fd, ucon->etype);
-    else
-        fprintf(fd, "\t.byte %d /* no union type */\n", Tybad);
-}
-
-/* on x86, unaligned pointers are cheap. we shouldn't be introspecting too
- * much, so tentatively, we'll just generate packed data.
- */
-static void gentydesc(FILE *fd, Type *ty)
-{
-    char buf[512];
-    uint8_t tt;
-    Node *sz;
     size_t i;
 
-    /* names are pulled out of line */
-    tt = ty->type;
-    /* tyvars can get tagged, but aren't desired */
-    if (ty->type == Tyvar)
+    if (!b)
         return;
-    if (ty->type == Tyname)
-        tt |= Tdindirect;
-    fprintf(fd, "\t.byte %d\n", tt);
-    switch (ty->type) {
-        case Ntypes: case Tyvar: case Tybad: case Typaram:
-        case Tygeneric: case Tyunres:
-            die("invalid type in tydesc");    break;
-
-        case Tyvoid: case Tychar: case Tybool: case Tyint8:
-        case Tyint16: case Tyint: case Tyint32: case Tyint64:
-        case Tylong: case Tybyte: case Tyuint8: case Tyuint16:
-        case Tyuint: case Tyuint32: case Tyuint64: case Tyulong:
-        case Tyflt32: case Tyflt64: case Tyvalist:
+    if (b->lbl) {
+        if (b->isglobl)
+            fprintf(fd, ".globl %s%s\n", Symprefix, b->lbl);
+        fprintf(fd, "%s%s:\n", Symprefix, b->lbl);
+    }
+    switch (b->type) {
+        case Bti8:
+            fprintf(fd, "\t.byte %zd\n", b->ival);
             break;
-
-        case Typtr:
-            gentydesc(fd, ty->sub[0]);
+        case Bti16:
+            fprintf(fd, "\t.short %zd\n", b->ival);
             break;
-        case Tyslice:
-            gentydesc(fd, ty->sub[0]);
+        case Bti32:
+            fprintf(fd, "\t.long %zd\n", b->ival);
             break;
-        case Tyarray:
-            ty->asize = fold(ty->asize, 1);
-            sz = ty->asize;
-            if (sz) {
-                assert(sz->type == Nexpr);
-                sz = sz->expr.args[0];
-                assert(sz->type == Nlit && sz->lit.littype == Lint);
-                fprintf(fd, "\t.quad %lld /* array size */\n", (vlong)sz->lit.intval);
-            } else {
-                fprintf(fd, "\t.quad -1 /* array size */\n");
-            }
-
-            gentydesc(fd, ty->sub[0]);
+        case Bti64:
+            fprintf(fd, "\t.quad %zd\n", b->ival);
             break;
-        case Tyfunc:
-            fprintf(fd, "\t.byte %zd /* nargs + ret */\n", ty->nsub);
-            for (i = 0; i < ty->nsub; i++)
-                gentydesc(fd, ty->sub[i]);
+        case Btimin:
+            encodemin(fd, b->ival);
             break;
-        case Tytuple:
-            fprintf(fd, "\t.byte %zd\n", ty->nsub);
-            for (i = 0; i < ty->nsub; i++)
-                gentydesc(fd, ty->sub[i]);
+        case Btref:
+            fprintf(fd, "\t.quad %s%s\n", Symprefix, b->ref);
             break;
-        case Tystruct:
-            fprintf(fd, "\t.quad %zd\n", ty->nmemb);
-            for (i = 0; i < ty->nmemb; i++)
-                genstructmemb(fd, ty->sdecls[i]);
+        case Btbytes:
+            writebytes(fd, b->bytes.buf, b->bytes.len);
             break;
-        case Tyunion:
-            fprintf(fd, "\t.quad %zd\n", ty->nmemb);
-            for (i = 0; i < ty->nmemb; i++)
-                genunionmemb(fd, ty->udecls[i]);
+        case Btseq:
+            for (i = 0; i < b->seq.nsub; i++)
+                gentyblob(fd, b->seq.sub[i]);
             break;
-        case Tyname:
-            fprintf(fd, "\t.quad %s%s\n", Symprefix, tydescid(buf, sizeof buf, ty));
-            break;
     }
 }
 
-static void gentype(FILE *fd, Type *ty)
+void gentype(FILE *fd, Type *ty)
 {
-    char buf[512];
+    Blob *b;
 
-    tydescid(buf, sizeof buf, ty);
-    if (ty->type == Tyname) {
-        if (hasparams(ty))
-            return;
-        if (ty->vis == Visexport)
-            fprintf(fd, ".globl %s%s /* tid: %d */\n", Symprefix, buf, ty->tid);
-    }
-    fprintf(fd, "%s%s:\n", Symprefix, buf);
-    fprintf(fd, "\t.quad %s$data\n", buf);
-    fprintf(fd, "\t.quad %s$end - %s$data\n", buf, buf);
-    fprintf(fd, "%s$data:\n", buf);
-    if (ty->type == Tyname) {
-        fprintf(fd, "\t.byte %d\n", ty->type);
-        gennamevec(fd, ty->name);
-        gentydesc(fd, ty->sub[0]);
-    } else {
-        gentydesc(fd, ty);
-    }
-    fprintf(fd, "%s$end:\n\n", buf);
+    if (ty->type == Tyvar)
+        return;
+    b = tydescblob(ty);
+    gentyblob(fd, b);
 }
 
 void gengas(Node *file, char *out)
--- a/6/typeinfo.c
+++ b/6/typeinfo.c
@@ -15,7 +15,231 @@
 #include "asm.h"
 #include "../config.h"
 
+#define Tdindirect 0x80
 
+Blob *tydescsub(Type *ty);
+
+static Blob *mkblobi(Blobtype type, uint64_t ival)
+{
+    Blob *b;
+
+    b = zalloc(sizeof(Blob));
+    b->type = type;
+    b->ival = ival;
+    return b;
+}
+
+static Blob *mkblobbytes(char *buf, size_t len)
+{
+    Blob *b;
+
+    b = zalloc(sizeof(Blob));
+    b->type = Btbytes;
+    b->bytes.len = len;
+    b->bytes.buf = buf;
+    return b;
+}
+
+static Blob *mkblobseq(Blob **sub, size_t nsub)
+{
+    Blob *b;
+
+    b = zalloc(sizeof(Blob));
+    b->type = Btseq;
+    b->seq.nsub = nsub;
+    b->seq.sub = sub;
+    return b;
+}
+
+static Blob *mkblobref(char *lbl)
+{
+    Blob *b;
+
+    b = zalloc(sizeof(Blob));
+    b->type = Btref;
+    b->ref = strdup(lbl);
+    return b;
+}
+
+static 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");
+    }
+}
+
+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);
+        snprintf(buf, len, "%s.%s", n->name.ns, n->name.name);
+    } else {
+        len = strlen(n->name.name);
+        buf = xalloc(len + 1);
+        snprintf(buf, len, "%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(Bti8, Tybad));
+}
+
+Blob *tydescsub(Type *ty)
+{
+    Blob **sub, *sz, *bt, *b;
+    size_t i, nsub;
+    char buf[512];
+    uint8_t tt;
+    Node *len;
+
+    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;
+
+    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 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 Tylong: case Tybyte: case Tyuint8: case Tyuint16:
+        case Tyuint: case Tyuint32: case Tyuint64: case Tyulong:
+        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:
+            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:
+            lappend(&sub, &nsub, mkblobi(Btimin, ty->nsub));
+            for (i = 0; i < ty->nsub; i++)
+                lappend(&sub, &nsub, tydescsub(ty->sub[i]));
+            break;
+        case Tystruct:
+            lappend(&sub, &nsub, mkblobi(Btimin, ty->nmemb));
+            for (i = 0; i < ty->nmemb; i++)
+                structmemb(&sub, &nsub, ty->sdecls[i]);
+            break;
+        case Tyunion:
+            lappend(&sub, &nsub, mkblobi(Btimin, ty->nmemb));
+            for (i = 0; i < ty->nmemb; i++)
+                unionmemb(&sub, &nsub, ty->udecls[i]);
+            break;
+        case Tyname:
+            i = snprintf(buf, sizeof buf, "%s", Symprefix);
+            tydescid(buf + i, sizeof buf - i, ty);
+            lappend(&sub, &nsub, mkblobref(buf));
+            break;
+    }
+    b = mkblobseq(sub, nsub);
+    sz->ival = blobsz(b);
+    linsert(&b->seq.sub, &b->seq.nsub, 0, sz);
+    return b;
+}
+
+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 = tydescsub(ty->sub[0]);
+        sz->ival = blobsz(sub);
+        lappend(&b->seq.sub, &b->seq.nsub, mkblobi(Bti8, Tyname));
+        lappend(&b->seq.sub, &b->seq.nsub, sz);
+        lappend(&b->seq.sub, &b->seq.nsub, sub);
+        if (ty->vis == Visexport)
+            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;