shithub: mc

Download patch

ref: b85c69ca0c686edc76fcf4bb2da54e3b5263bbba
parent: 2433e863b1b3e802f38dd6db534b52867f670269
author: Ori Bernstein <[email protected]>
date: Sun Dec 21 13:41:45 EST 2014

First attempt at supporting plan9 assemblers.

--- a/6/Makefile
+++ b/6/Makefile
@@ -1,6 +1,8 @@
 INSTBIN=6m
 OBJ= \
 	gen.o \
+	gengas.o \
+	genp9.o \
 	isel.o \
 	locs.o \
 	main.o \
--- a/6/asm.h
+++ b/6/asm.h
@@ -20,7 +20,7 @@
 } AsmOp;
 
 typedef enum {
-#define Reg(r, name, mode) r,
+#define Reg(r, gasname, p9name, mode) r,
 #include "regs.def"
 #undef Reg
     Nreg
@@ -54,6 +54,11 @@
     Nclass,
 } Rclass;
 
+typedef enum {
+    Gnugas,
+    Plan9,
+} Asmsyntax;
+
 /* a register, label, or memory location */
 struct Loc {
     Loctype type; /* the type of loc */
@@ -186,7 +191,6 @@
 };
 
 /* globals */
-extern char *modenames[];
 extern Type *tyintptr;
 extern Type *tyword;
 extern Type *tyvoid;
@@ -197,7 +201,9 @@
 
 void simpglobl(Node *dcl, Htab *globls, Func ***fn, size_t *nfn, Node ***blob, size_t *nblob);
 void selfunc(Isel *is, Func *fn, Htab *globls, Htab *strtab);
-void gen(Node *file, char *out);
+void gen(Asmsyntax syn, Node *file, char *out);
+void gengas(Node *file, char *out);
+void genp9(Node *file, char *out);
 
 /* location generation */
 extern size_t maxregid;
@@ -222,13 +228,10 @@
 
 /* emitting instructions */
 Insn *mkinsn(AsmOp op, ...);
-void iprintf(FILE *fd, Insn *insn);
-void locprint(FILE *fd, Loc *l, char spec);
+void dbgiprintf(FILE *fd, Insn *insn);
+void dbglocprint(FILE *fd, Loc *l, char spec);
 
 /* register allocation */
-extern char *regnames[]; /* name table */
-extern Mode regmodes[];  /* mode table */
-extern size_t modesize[]; /* mode size table */
 void regalloc(Isel *s);
 Rclass rclass(Loc *l);
 
--- a/6/gen.c
+++ b/6/gen.c
@@ -14,557 +14,11 @@
 #include "asm.h"
 #include "../config.h"
 
-/* string tables */
-char *gasinsnfmt[] = {
-#define Insn(val, gasfmt, p9fmt, use, def) gasfmt,
-#include "insns.def"
-#undef Insn
-};
-
-char *p9insnfmt[] = {
-#define Insn(val, gasfmt, p9fmt, use, def) p9fmt,
-#include "insns.def"
-#undef Insn
-};
-
-char* gasmodenames[] = {
-  [ModeB] = "b",
-  [ModeW] = "w",
-  [ModeL] = "l",
-  [ModeQ] = "q",
-  [ModeF] = "s",
-  [ModeD] = "d"
-};
-
-char* p9modenames[] = {
-  [ModeB] = "B",
-  [ModeW] = "W",
-  [ModeL] = "L",
-  [ModeQ] = "Q",
-  [ModeF] = "S",
-  [ModeD] = "D"
-};
-
-static size_t writeblob(FILE *fd, Htab *globls, Htab *strtab, Node *blob);
-
-static void fillglobls(Stab *st, Htab *globls)
+void gen(Asmsyntax syn, Node *file, char *out)
 {
-    void **k;
-    size_t i, nk;
-    Stab *stab;
-    Node *s;
-
-    k = htkeys(st->dcl, &nk);
-    for (i = 0; i < nk; i++) {
-        s = htget(st->dcl, k[i]);
-        htput(globls, s, asmname(s->decl.name));
+    switch (syn) {
+        case Plan9:     genp9(file, out);       break;
+        case Gnugas:    gengas(file, out);      break;
+        default:        die("unknown target");  break;
     }
-    free(k);
-
-    k = htkeys(st->ns, &nk);
-    for (i = 0; i < nk; i++) {
-        stab = htget(st->ns, k[i]);
-        fillglobls(stab, globls);
-    }
-    free(k);
-}
-
-static void initconsts(Htab *globls)
-{
-    Type *ty;
-    Node *name;
-    Node *dcl;
-
-    tyintptr = mktype(Zloc, Tyuint64);
-    tyword = mktype(Zloc, Tyuint);
-    tyvoid = mktype(Zloc, Tyvoid);
-
-    ty = mktyfunc(Zloc, NULL, 0, mktype(Zloc, Tyvoid));
-    name = mknsname(Zloc, "_rt", "abort_oob");
-    dcl = mkdecl(Zloc, name, ty);
-    dcl->decl.isconst = 1;
-    dcl->decl.isextern = 1;
-    htput(globls, dcl, asmname(dcl->decl.name));
-
-    abortoob = mkexpr(Zloc, Ovar, name, NULL);
-    abortoob->expr.type = ty;
-    abortoob->expr.did = dcl->decl.did;
-    abortoob->expr.isconst = 1;
-}
-
-void gasprintmem(FILE *fd, Loc *l, char spec)
-{
-    if (l->type == Locmem) {
-        if (l->mem.constdisp)
-            fprintf(fd, "%ld", l->mem.constdisp);
-    } else {
-        if (l->mem.lbldisp)
-            fprintf(fd, "%s", l->mem.lbldisp);
-    }
-    if (l->mem.base) {
-        fprintf(fd, "(");
-        locprint(fd, l->mem.base, 'r');
-        if (l->mem.idx) {
-            fprintf(fd, ",");
-            locprint(fd, l->mem.idx, 'r');
-        }
-        if (l->mem.scale > 1)
-            fprintf(fd, ",%d", l->mem.scale);
-        if (l->mem.base)
-            fprintf(fd, ")");
-    } else if (l->type != Locmeml) {
-        die("Only locmeml can have unspecified base reg");
-    }
-}
-
-void p9printmem(FILE *fd, Loc *l, char spec)
-{
-    gasprintmem(fd, l, spec);
-}
-
-void locprint(FILE *fd, Loc *l, char spec)
-{
-    int isp9;
-
-    isp9 = isupper(spec);
-    spec = tolower(spec);
-    assert(l->mode);
-    switch (l->type) {
-        case Loclitl:
-            assert(spec == 'i' || spec == 'x' || spec == 'u');
-            fprintf(fd, "$%s", l->lbl);
-            break;
-        case Loclbl:
-            assert(spec == 'm' || spec == 'v' || spec == 'x');
-            fprintf(fd, "%s", l->lbl);
-            break;
-        case Locreg:
-            assert((spec == 'r' && isintmode(l->mode)) || 
-                   (spec == 'f' && isfloatmode(l->mode)) ||
-                   spec == 'v' ||
-                   spec == 'x' ||
-                   spec == 'u');
-            if (l->reg.colour == Rnone)
-                fprintf(fd, "%%P.%zd%s", l->reg.id, gasmodenames[l->mode]);
-            else
-                fprintf(fd, "%s", regnames[l->reg.colour]);
-            break;
-        case Locmem:
-        case Locmeml:
-            assert(spec == 'm' || spec == 'v' || spec == 'x');
-            if (isp9)
-                p9printmem(fd, l, spec);
-            else
-                gasprintmem(fd, l, spec);
-            break;
-        case Loclit:
-            assert(spec == 'i' || spec == 'x' || spec == 'u');
-            fprintf(fd, "$%ld", l->lit);
-            break;
-        case Locnone:
-            die("Bad location in locprint()");
-            break;
-    }
-}
-
-static int issubreg(Loc *a, Loc *b)
-{
-    return rclass(a) == rclass(b) && a->mode != b->mode;
-}
-
-void iprintf(FILE *fd, Insn *insn)
-{
-    char *p;
-    int i;
-    int modeidx;
-
-    /* x64 has a quirk; it has no movzlq because mov zero extends. This
-     * means that we need to do a movl when we really want a movzlq. Since
-     * we don't know the name of the reg to use, we need to sub it in when
-     * writing... */
-    switch (insn->op) {
-        case Imovzx:
-            if (insn->args[0]->mode == ModeL && insn->args[1]->mode == ModeQ) {
-                if (insn->args[1]->reg.colour) {
-                    insn->op = Imov;
-                    insn->args[1] = coreg(insn->args[1]->reg.colour, ModeL);
-                }
-            }
-            break;
-        case Imovs:
-            if (insn->args[0]->reg.colour == Rnone || insn->args[1]->reg.colour == Rnone)
-                break;
-            /* moving a reg to itself is dumb. */
-            if (insn->args[0]->reg.colour == insn->args[1]->reg.colour)
-                return;
-            break;
-        case Imov:
-            assert(!isfloatmode(insn->args[0]->mode));
-            if (insn->args[0]->type != Locreg || insn->args[1]->type != Locreg)
-                break;
-            if (insn->args[0]->reg.colour == Rnone || insn->args[1]->reg.colour == Rnone)
-                break;
-            /* if one reg is a subreg of another, we can just use the right
-             * mode to move between them. */
-            if (issubreg(insn->args[0], insn->args[1]))
-                insn->args[0] = coreg(insn->args[0]->reg.colour, insn->args[1]->mode);
-            /* moving a reg to itself is dumb. */
-            if (insn->args[0]->reg.colour == insn->args[1]->reg.colour)
-                return;
-            break;
-        default:
-            break;
-    }
-    p = insnfmt[insn->op];
-    i = 0;
-    modeidx = 0;
-    for (; *p; p++) {
-        if (*p !=  '%') {
-            fputc(*p, fd);
-            continue;
-        }
-
-        /* %-formating */
-        p++;
-        switch (*p) {
-            case '\0':
-                goto done; /* skip the final p++ */
-            case 'r': /* int register */
-            case 'f': /* float register */
-            case 'm': /* memory */
-            case 'i': /* imm */
-            case 'v': /* reg/mem */
-            case 'u': /* reg/imm */
-            case 'x': /* reg/mem/imm */
-                locprint(fd, insn->args[i], *p);
-                i++;
-                break;
-            case 'R': /* int register */
-            case 'F': /* float register */
-            case 'M': /* memory */
-            case 'I': /* imm */
-            case 'V': /* reg/mem */
-            case 'U': /* reg/imm */
-            case 'X': /* reg/mem/imm */
-                locprint(fd, insn->args[i], *p);
-                i++;
-                break;
-            case 't':
-            case 'T':
-            default:
-                /* the  asm description uses 1-based indexing, so that 0
-                 * can be used as a sentinel. */
-                if (isdigit(*p))
-                    modeidx = strtol(p, &p, 10) - 1;
-
-                if (*p == 't')
-                    fputs(gasmodenames[insn->args[modeidx]->mode], fd);
-                else if (*p == 'T')
-                    fputs(p9modenames[insn->args[modeidx]->mode], fd);
-                else
-                    die("Invalid %%-specifier '%c'", *p);
-                break;
-        }
-    }
-done:
-    return;
-}
-
-
-static void writebytes(FILE *fd, char *p, size_t sz)
-{
-    size_t i;
-
-    for (i = 0; i < sz; i++) {
-        if (i % 60 == 0)
-            fprintf(fd, "\t.ascii \"");
-        if (p[i] == '"' || p[i] == '\\')
-            fprintf(fd, "\\");
-        if (isprint(p[i]))
-            fprintf(fd, "%c", p[i]);
-        else
-            fprintf(fd, "\\%03o", (uint8_t)p[i] & 0xff);
-        /* line wrapping for readability */
-        if (i % 60 == 59 || i == sz - 1)
-            fprintf(fd, "\"\n");
-    }
-}
-
-static size_t writelit(FILE *fd, Htab *strtab, Node *v, Type *ty)
-{
-    char buf[128];
-    char *lbl;
-    size_t sz;
-    char *intsz[] = {
-        [1] = ".byte",
-        [2] = ".short",
-        [4] = ".long",
-        [8] = ".quad"
-    };
-    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:      fprintf(fd, "\t%s %lld\n", intsz[sz], v->lit.intval);    break;
-        case Lbool:     fprintf(fd, "\t.byte %d\n", v->lit.boolval);     break;
-        case Lchr:      fprintf(fd, "\t.long %d\n",  v->lit.chrval);     break;
-        case Lflt:
-                if (tybase(v->lit.type)->type == Tyflt32) {
-                    u.fv = v->lit.fltval;
-                    fprintf(fd, "\t.long 0x%" PRIx32 "\n", u.lv);
-                } else if (tybase(v->lit.type)->type == Tyflt64) {
-                    u.dv = v->lit.fltval;
-                    fprintf(fd, "\t.quad 0x%" PRIx64 "\n", u.qv);
-                }
-                break;
-        case Lstr:
-           if (hthas(strtab, &v->lit.strval)) {
-               lbl = htget(strtab, &v->lit.strval);
-           } else {
-               lbl = genlblstr(buf, sizeof buf);
-               htput(strtab, &v->lit.strval, strdup(lbl));
-           }
-           fprintf(fd, "\t.quad %s\n", lbl);
-           fprintf(fd, "\t.quad %zd\n", 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 writepad(FILE *fd, size_t sz)
-{
-    assert((ssize_t)sz >= 0);
-    if (sz > 0)
-        fprintf(fd, "\t.fill %zd,1,0\n", sz);
-    return sz;
-}
-
-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 size_t writeslice(FILE *fd, 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);
-    fprintf(fd, "\t.quad %s + (%zd*%zd)\n", lbl, loval, sz);
-    fprintf(fd, "\t.quad %zd\n", (hival - loval));
-    return size(n);
-}
-
-static size_t writestruct(FILE *fd, Htab *globls, Htab *strtab, Node *n)
-{
-    Type *t;
-    Node **dcl;
-    int found;
-    size_t i, j;
-    size_t sz, pad, end;
-    size_t ndcl;
-
-    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]));
-        sz += writepad(fd, pad - sz);
-        found = 0;
-        for (j = 0; j < n->expr.nargs; j++)
-            if (!strcmp(namestr(n->expr.args[j]->expr.idx), declname(dcl[i]))) {
-                found = 1;
-                sz += writeblob(fd, globls, strtab, n->expr.args[j]);
-            }
-        if (!found)
-            sz += writepad(fd, size(dcl[i]));
-    }
-    end = alignto(sz, t);
-    sz += writepad(fd, end - sz);
-    return sz;
-}
-static size_t writeblob(FILE *fd, Htab *globls, Htab *strtab, Node *n)
-{
-    size_t i, sz;
-
-    switch(exprop(n)) {
-        case Otup:
-        case Oarr:
-            sz = 0;
-            for (i = 0; i < n->expr.nargs; i++)
-                sz += writeblob(fd, globls, strtab, n->expr.args[i]);
-            break;
-        case Ostruct:
-            sz = writestruct(fd, globls, strtab, n);
-            break;
-        case Olit:
-            sz = writelit(fd, strtab, n->expr.args[0], exprtype(n));
-            break;
-        case Oslice:
-            sz = writeslice(fd, globls, strtab, n);
-            break;
-        default:
-            dump(n, stdout);
-            die("Nonliteral initializer for global");
-            break;
-    }
-    return sz;
-}
-
-void genstrings(FILE *fd, Htab *strtab)
-{
-    void **k;
-    Str *s;
-    size_t i, nk;
-
-    k = htkeys(strtab, &nk);
-    for (i = 0; i < nk; i++) {
-        s = k[i];
-        fprintf(fd, "%s:\n", (char*)htget(strtab, k[i]));
-        writebytes(fd, s->buf, s->len);
-    }
-}
-
-
-static void writeasm(FILE *fd, Isel *s, Func *fn)
-{
-    size_t i, j;
-
-    if (fn->isexport || !strcmp(fn->name, Symprefix "main"))
-        fprintf(fd, ".globl %s\n", fn->name);
-    fprintf(fd, "%s:\n", fn->name);
-    for (j = 0; j < s->cfg->nbb; j++) {
-        if (!s->bb[j])
-            continue;
-        for (i = 0; i < s->bb[j]->nlbls; i++)
-            fprintf(fd, "%s:\n", s->bb[j]->lbls[i]);
-        for (i = 0; i < s->bb[j]->ni; i++)
-            iprintf(fd, s->bb[j]->il[i]);
-    }
-}
-
-void genblob(FILE *fd, Node *blob, Htab *globls, Htab *strtab)
-{
-    char *lbl;
-
-    /* lits and such also get wrapped in decls */
-    assert(blob->type == Ndecl);
-
-    lbl = htget(globls, blob);
-    if (blob->decl.vis != Visintern)
-        fprintf(fd, ".globl %s\n", lbl);
-    fprintf(fd, "%s:\n", lbl);
-    if (blob->decl.init)
-        writeblob(fd, globls, strtab, blob->decl.init);
-    else
-        writepad(fd, size(blob));
-}
-
-/* genfunc requires all nodes in 'nl' to map cleanly to operations that are
- * natively supported, as promised in the output of reduce().  No 64-bit
- * operations on x32, no structures, and so on. */
-void genfunc(FILE *fd, Func *fn, Htab *globls, Htab *strtab)
-{
-    Isel is = {0,};
-
-    is.reglocs = mkht(varhash, vareq);
-    is.stkoff = fn->stkoff;
-    is.globls = globls;
-    is.ret = fn->ret;
-    is.cfg = fn->cfg;
-
-    selfunc(&is, fn, globls, strtab);
-    if (debugopt['i'])
-        writeasm(stdout, &is, fn);
-    writeasm(fd, &is, fn);
-}
-
-void gen(Node *file, char *out)
-{
-    Htab *globls, *strtab;
-    Node *n, **blob;
-    Func **fn;
-    size_t nfn, nblob;
-    size_t i;
-    FILE *fd;
-
-    /* ensure that all physical registers have a loc created before any
-     * other locs, so that locmap[Physreg] maps to the Loc for the physreg
-     * in question */
-    for (i = 0; i < Nreg; i++)
-        locphysreg(i);
-
-    fn = NULL;
-    nfn = 0;
-    blob = NULL;
-    nblob = 0;
-    globls = mkht(varhash, vareq);
-    initconsts(globls);
-
-    /* We need to define all global variables before use */
-    fillglobls(file->file.globls, globls);
-
-    pushstab(file->file.globls);
-    for (i = 0; i < file->file.nstmts; i++) {
-        n = file->file.stmts[i];
-        switch (n->type) {
-            case Nuse: /* nothing to do */ 
-            case Nimpl:
-                break;
-            case Ndecl:
-                simpglobl(n, globls, &fn, &nfn, &blob, &nblob);
-                break;
-            default:
-                die("Bad node %s in toplevel", nodestr(n->type));
-                break;
-        }
-    }
-    popstab();
-
-    fd = fopen(out, "w");
-    if (!fd)
-        die("Couldn't open fd %s", out);
-
-    strtab = mkht(strlithash, strliteq);
-    fprintf(fd, ".data\n");
-    for (i = 0; i < nblob; i++)
-        genblob(fd, blob[i], globls, strtab);
-    fprintf(fd, ".text\n");
-    for (i = 0; i < nfn; i++)
-        genfunc(fd, fn[i], globls, strtab);
-    genstrings(fd, strtab);
-    fclose(fd);
 }
--- /dev/null
+++ b/6/gengas.c
@@ -1,0 +1,557 @@
+#include <stdlib.h>
+#include <stdio.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 char *insnfmt[] = {
+#define Insn(val, gasfmt, p9fmt, use, def) gasfmt,
+#include "insns.def"
+#undef Insn
+};
+
+static char *regnames[] = {
+#define Reg(r, gasname, p9name, mode) gasname,
+#include "regs.def"
+#undef Reg
+};
+
+static char* modenames[] = {
+  [ModeB] = "b",
+  [ModeW] = "w",
+  [ModeL] = "l",
+  [ModeQ] = "q",
+  [ModeF] = "s",
+  [ModeD] = "d"
+};
+
+static size_t writeblob(FILE *fd, Htab *globls, Htab *strtab, Node *blob);
+static void locprint(FILE *fd, Loc *l, char spec);
+
+static void fillglobls(Stab *st, Htab *globls)
+{
+    void **k;
+    size_t i, nk;
+    Stab *stab;
+    Node *s;
+
+    k = htkeys(st->dcl, &nk);
+    for (i = 0; i < nk; i++) {
+        s = htget(st->dcl, k[i]);
+        htput(globls, s, asmname(s->decl.name));
+    }
+    free(k);
+
+    k = htkeys(st->ns, &nk);
+    for (i = 0; i < nk; i++) {
+        stab = htget(st->ns, k[i]);
+        fillglobls(stab, globls);
+    }
+    free(k);
+}
+
+static void initconsts(Htab *globls)
+{
+    Type *ty;
+    Node *name;
+    Node *dcl;
+
+    tyintptr = mktype(Zloc, Tyuint64);
+    tyword = mktype(Zloc, Tyuint);
+    tyvoid = mktype(Zloc, Tyvoid);
+
+    ty = mktyfunc(Zloc, NULL, 0, mktype(Zloc, Tyvoid));
+    name = mknsname(Zloc, "_rt", "abort_oob");
+    dcl = mkdecl(Zloc, name, ty);
+    dcl->decl.isconst = 1;
+    dcl->decl.isextern = 1;
+    htput(globls, dcl, asmname(dcl->decl.name));
+
+    abortoob = mkexpr(Zloc, Ovar, name, NULL);
+    abortoob->expr.type = ty;
+    abortoob->expr.did = dcl->decl.did;
+    abortoob->expr.isconst = 1;
+}
+
+void printmem(FILE *fd, Loc *l, char spec)
+{
+    if (l->type == Locmem) {
+        if (l->mem.constdisp)
+            fprintf(fd, "%ld", l->mem.constdisp);
+    } else {
+        if (l->mem.lbldisp)
+            fprintf(fd, "%s", l->mem.lbldisp);
+    }
+    if (l->mem.base) {
+        fprintf(fd, "(");
+        locprint(fd, l->mem.base, 'r');
+        if (l->mem.idx) {
+            fprintf(fd, ",");
+            locprint(fd, l->mem.idx, 'r');
+        }
+        if (l->mem.scale > 1)
+            fprintf(fd, ",%d", l->mem.scale);
+        if (l->mem.base)
+            fprintf(fd, ")");
+    } else if (l->type != Locmeml) {
+        die("Only locmeml can have unspecified base reg");
+    }
+}
+
+static void locprint(FILE *fd, Loc *l, char spec)
+{
+    assert(l->mode);
+    switch (l->type) {
+        case Loclitl:
+            assert(spec == 'i' || spec == 'x' || spec == 'u');
+            fprintf(fd, "$%s", l->lbl);
+            break;
+        case Loclbl:
+            assert(spec == 'm' || spec == 'v' || spec == 'x');
+            fprintf(fd, "%s", l->lbl);
+            break;
+        case Locreg:
+            assert((spec == 'r' && isintmode(l->mode)) || 
+                   (spec == 'f' && isfloatmode(l->mode)) ||
+                   spec == 'v' ||
+                   spec == 'x' ||
+                   spec == 'u');
+            if (l->reg.colour == Rnone)
+                fprintf(fd, "%%P.%zd%s", l->reg.id, modenames[l->mode]);
+            else
+                fprintf(fd, "%s", regnames[l->reg.colour]);
+            break;
+        case Locmem:
+        case Locmeml:
+            assert(spec == 'm' || spec == 'v' || spec == 'x');
+            printmem(fd, l, spec);
+            break;
+        case Loclit:
+            assert(spec == 'i' || spec == 'x' || spec == 'u');
+            fprintf(fd, "$%ld", l->lit);
+            break;
+        case Locnone:
+            die("Bad location in locprint()");
+            break;
+    }
+}
+
+static int issubreg(Loc *a, Loc *b)
+{
+    return rclass(a) == rclass(b) && a->mode != b->mode;
+}
+
+void iprintf(FILE *fd, Insn *insn)
+{
+    char *p;
+    int i;
+    int modeidx;
+
+    /* x64 has a quirk; it has no movzlq because mov zero extends. This
+     * means that we need to do a movl when we really want a movzlq. Since
+     * we don't know the name of the reg to use, we need to sub it in when
+     * writing... */
+    switch (insn->op) {
+        case Imovzx:
+            if (insn->args[0]->mode == ModeL && insn->args[1]->mode == ModeQ) {
+                if (insn->args[1]->reg.colour) {
+                    insn->op = Imov;
+                    insn->args[1] = coreg(insn->args[1]->reg.colour, ModeL);
+                }
+            }
+            break;
+        case Imovs:
+            if (insn->args[0]->reg.colour == Rnone || insn->args[1]->reg.colour == Rnone)
+                break;
+            /* moving a reg to itself is dumb. */
+            if (insn->args[0]->reg.colour == insn->args[1]->reg.colour)
+                return;
+            break;
+        case Imov:
+            assert(!isfloatmode(insn->args[0]->mode));
+            if (insn->args[0]->type != Locreg || insn->args[1]->type != Locreg)
+                break;
+            if (insn->args[0]->reg.colour == Rnone || insn->args[1]->reg.colour == Rnone)
+                break;
+            /* if one reg is a subreg of another, we can just use the right
+             * mode to move between them. */
+            if (issubreg(insn->args[0], insn->args[1]))
+                insn->args[0] = coreg(insn->args[0]->reg.colour, insn->args[1]->mode);
+            /* moving a reg to itself is dumb. */
+            if (insn->args[0]->reg.colour == insn->args[1]->reg.colour)
+                return;
+            break;
+        default:
+            break;
+    }
+    p = insnfmt[insn->op];
+    i = 0;
+    modeidx = 0;
+    for (; *p; p++) {
+        if (*p !=  '%') {
+            fputc(*p, fd);
+            continue;
+        }
+
+        /* %-formating */
+        p++;
+        switch (*p) {
+            case '\0':
+                goto done; /* skip the final p++ */
+            case 'r': /* int register */
+            case 'f': /* float register */
+            case 'm': /* memory */
+            case 'i': /* imm */
+            case 'v': /* reg/mem */
+            case 'u': /* reg/imm */
+            case 'x': /* reg/mem/imm */
+                locprint(fd, insn->args[i], *p);
+                i++;
+                break;
+            case 'R': /* int register */
+            case 'F': /* float register */
+            case 'M': /* memory */
+            case 'I': /* imm */
+            case 'V': /* reg/mem */
+            case 'U': /* reg/imm */
+            case 'X': /* reg/mem/imm */
+                locprint(fd, insn->args[i], *p);
+                i++;
+                break;
+            case 't':
+            case 'T':
+            default:
+                /* the  asm description uses 1-based indexing, so that 0
+                 * can be used as a sentinel. */
+                if (isdigit(*p))
+                    modeidx = strtol(p, &p, 10) - 1;
+
+                if (*p == 't')
+                    fputs(modenames[insn->args[modeidx]->mode], fd);
+                else
+                    die("Invalid %%-specifier '%c'", *p);
+                break;
+        }
+    }
+done:
+    return;
+}
+
+
+static void writebytes(FILE *fd, char *p, size_t sz)
+{
+    size_t i;
+
+    for (i = 0; i < sz; i++) {
+        if (i % 60 == 0)
+            fprintf(fd, "\t.ascii \"");
+        if (p[i] == '"' || p[i] == '\\')
+            fprintf(fd, "\\");
+        if (isprint(p[i]))
+            fprintf(fd, "%c", p[i]);
+        else
+            fprintf(fd, "\\%03o", (uint8_t)p[i] & 0xff);
+        /* line wrapping for readability */
+        if (i % 60 == 59 || i == sz - 1)
+            fprintf(fd, "\"\n");
+    }
+}
+
+static size_t writelit(FILE *fd, Htab *strtab, Node *v, Type *ty)
+{
+    char buf[128];
+    char *lbl;
+    size_t sz;
+    char *intsz[] = {
+        [1] = ".byte",
+        [2] = ".short",
+        [4] = ".long",
+        [8] = ".quad"
+    };
+    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:      fprintf(fd, "\t%s %lld\n", intsz[sz], v->lit.intval);    break;
+        case Lbool:     fprintf(fd, "\t.byte %d\n", v->lit.boolval);     break;
+        case Lchr:      fprintf(fd, "\t.long %d\n",  v->lit.chrval);     break;
+        case Lflt:
+                if (tybase(v->lit.type)->type == Tyflt32) {
+                    u.fv = v->lit.fltval;
+                    fprintf(fd, "\t.long 0x%" PRIx32 "\n", u.lv);
+                } else if (tybase(v->lit.type)->type == Tyflt64) {
+                    u.dv = v->lit.fltval;
+                    fprintf(fd, "\t.quad 0x%" PRIx64 "\n", u.qv);
+                }
+                break;
+        case Lstr:
+           if (hthas(strtab, &v->lit.strval)) {
+               lbl = htget(strtab, &v->lit.strval);
+           } else {
+               lbl = genlblstr(buf, sizeof buf);
+               htput(strtab, &v->lit.strval, strdup(lbl));
+           }
+           fprintf(fd, "\t.quad %s\n", lbl);
+           fprintf(fd, "\t.quad %zd\n", 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 writepad(FILE *fd, size_t sz)
+{
+    assert((ssize_t)sz >= 0);
+    if (sz > 0)
+        fprintf(fd, "\t.fill %zd,1,0\n", sz);
+    return sz;
+}
+
+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 size_t writeslice(FILE *fd, 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);
+    fprintf(fd, "\t.quad %s + (%zd*%zd)\n", lbl, loval, sz);
+    fprintf(fd, "\t.quad %zd\n", (hival - loval));
+    return size(n);
+}
+
+static size_t writestruct(FILE *fd, Htab *globls, Htab *strtab, Node *n)
+{
+    Type *t;
+    Node **dcl;
+    int found;
+    size_t i, j;
+    size_t sz, pad, end;
+    size_t ndcl;
+
+    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]));
+        sz += writepad(fd, pad - sz);
+        found = 0;
+        for (j = 0; j < n->expr.nargs; j++)
+            if (!strcmp(namestr(n->expr.args[j]->expr.idx), declname(dcl[i]))) {
+                found = 1;
+                sz += writeblob(fd, globls, strtab, n->expr.args[j]);
+            }
+        if (!found)
+            sz += writepad(fd, size(dcl[i]));
+    }
+    end = alignto(sz, t);
+    sz += writepad(fd, end - sz);
+    return sz;
+}
+static size_t writeblob(FILE *fd, Htab *globls, Htab *strtab, Node *n)
+{
+    size_t i, sz;
+
+    switch(exprop(n)) {
+        case Otup:
+        case Oarr:
+            sz = 0;
+            for (i = 0; i < n->expr.nargs; i++)
+                sz += writeblob(fd, globls, strtab, n->expr.args[i]);
+            break;
+        case Ostruct:
+            sz = writestruct(fd, globls, strtab, n);
+            break;
+        case Olit:
+            sz = writelit(fd, strtab, n->expr.args[0], exprtype(n));
+            break;
+        case Oslice:
+            sz = writeslice(fd, globls, strtab, n);
+            break;
+        default:
+            dump(n, stdout);
+            die("Nonliteral initializer for global");
+            break;
+    }
+    return sz;
+}
+
+void genstrings(FILE *fd, Htab *strtab)
+{
+    void **k;
+    Str *s;
+    size_t i, nk;
+
+    k = htkeys(strtab, &nk);
+    for (i = 0; i < nk; i++) {
+        s = k[i];
+        fprintf(fd, "%s:\n", (char*)htget(strtab, k[i]));
+        writebytes(fd, s->buf, s->len);
+    }
+}
+
+
+static void writeasm(FILE *fd, Isel *s, Func *fn)
+{
+    size_t i, j;
+
+    if (fn->isexport || !strcmp(fn->name, Symprefix "main"))
+        fprintf(fd, ".globl %s\n", fn->name);
+    fprintf(fd, "%s:\n", fn->name);
+    for (j = 0; j < s->cfg->nbb; j++) {
+        if (!s->bb[j])
+            continue;
+        for (i = 0; i < s->bb[j]->nlbls; i++)
+            fprintf(fd, "%s:\n", s->bb[j]->lbls[i]);
+        for (i = 0; i < s->bb[j]->ni; i++)
+            iprintf(fd, s->bb[j]->il[i]);
+    }
+}
+
+void genblob(FILE *fd, Node *blob, Htab *globls, Htab *strtab)
+{
+    char *lbl;
+
+    /* lits and such also get wrapped in decls */
+    assert(blob->type == Ndecl);
+
+    lbl = htget(globls, blob);
+    if (blob->decl.vis != Visintern)
+        fprintf(fd, ".globl %s\n", lbl);
+    fprintf(fd, "%s:\n", lbl);
+    if (blob->decl.init)
+        writeblob(fd, globls, strtab, blob->decl.init);
+    else
+        writepad(fd, size(blob));
+}
+
+/* genfunc requires all nodes in 'nl' to map cleanly to operations that are
+ * natively supported, as promised in the output of reduce().  No 64-bit
+ * operations on x32, no structures, and so on. */
+void genfunc(FILE *fd, Func *fn, Htab *globls, Htab *strtab)
+{
+    Isel is = {0,};
+
+    is.reglocs = mkht(varhash, vareq);
+    is.stkoff = fn->stkoff;
+    is.globls = globls;
+    is.ret = fn->ret;
+    is.cfg = fn->cfg;
+
+    selfunc(&is, fn, globls, strtab);
+    if (debugopt['i'])
+        writeasm(stdout, &is, fn);
+    writeasm(fd, &is, fn);
+}
+
+void gengas(Node *file, char *out)
+{
+    Htab *globls, *strtab;
+    Node *n, **blob;
+    Func **fn;
+    size_t nfn, nblob;
+    size_t i;
+    FILE *fd;
+
+    /* ensure that all physical registers have a loc created before any
+     * other locs, so that locmap[Physreg] maps to the Loc for the physreg
+     * in question */
+    for (i = 0; i < Nreg; i++)
+        locphysreg(i);
+
+    fn = NULL;
+    nfn = 0;
+    blob = NULL;
+    nblob = 0;
+    globls = mkht(varhash, vareq);
+    initconsts(globls);
+
+    /* We need to define all global variables before use */
+    fillglobls(file->file.globls, globls);
+
+    pushstab(file->file.globls);
+    for (i = 0; i < file->file.nstmts; i++) {
+        n = file->file.stmts[i];
+        switch (n->type) {
+            case Nuse: /* nothing to do */ 
+            case Nimpl:
+                break;
+            case Ndecl:
+                simpglobl(n, globls, &fn, &nfn, &blob, &nblob);
+                break;
+            default:
+                die("Bad node %s in toplevel", nodestr(n->type));
+                break;
+        }
+    }
+    popstab();
+
+    fd = fopen(out, "w");
+    if (!fd)
+        die("Couldn't open fd %s", out);
+
+    strtab = mkht(strlithash, strliteq);
+    fprintf(fd, ".data\n");
+    for (i = 0; i < nblob; i++)
+        genblob(fd, blob[i], globls, strtab);
+    fprintf(fd, ".text\n");
+    for (i = 0; i < nfn; i++)
+        genfunc(fd, fn[i], globls, strtab);
+    genstrings(fd, strtab);
+    fclose(fd);
+}
+
+void dbglocprint(FILE *fd, Loc *l, char spec)
+{
+    locprint(fd, l, spec);
+}
+
+void dbgiprintf(FILE *fd, Insn *i)
+{
+    iprintf(fd, i);
+}
--- /dev/null
+++ b/6/genp9.c
@@ -1,0 +1,550 @@
+#include <stdlib.h>
+#include <stdio.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"
+
+/* string tables */
+static char *insnfmt[] = {
+#define Insn(val, gasfmt, p9fmt, use, def) p9fmt,
+#include "insns.def"
+#undef Insn
+};
+
+static char *regnames[] = {
+#define Reg(r, gasname, p9name, mode) p9name,
+#include "regs.def"
+#undef Reg
+};
+
+static char* modenames[] = {
+  [ModeB] = "B",
+  [ModeW] = "W",
+  [ModeL] = "L",
+  [ModeQ] = "Q",
+  [ModeF] = "S",
+  [ModeD] = "D"
+};
+
+static size_t writeblob(FILE *fd, char *name, size_t off, Htab *globls, Htab *strtab, Node *blob);
+static void locprint(FILE *fd, Loc *l, char spec);
+
+static void fillglobls(Stab *st, Htab *globls)
+{
+    void **k;
+    size_t i, nk;
+    Stab *stab;
+    Node *s;
+
+    k = htkeys(st->dcl, &nk);
+    for (i = 0; i < nk; i++) {
+        s = htget(st->dcl, k[i]);
+        htput(globls, s, asmname(s->decl.name));
+    }
+    free(k);
+
+    k = htkeys(st->ns, &nk);
+    for (i = 0; i < nk; i++) {
+        stab = htget(st->ns, k[i]);
+        fillglobls(stab, globls);
+    }
+    free(k);
+}
+
+static void initconsts(Htab *globls)
+{
+    Type *ty;
+    Node *name;
+    Node *dcl;
+
+    tyintptr = mktype(Zloc, Tyuint64);
+    tyword = mktype(Zloc, Tyuint);
+    tyvoid = mktype(Zloc, Tyvoid);
+
+    ty = mktyfunc(Zloc, NULL, 0, mktype(Zloc, Tyvoid));
+    name = mknsname(Zloc, "_rt", "abort_oob");
+    dcl = mkdecl(Zloc, name, ty);
+    dcl->decl.isconst = 1;
+    dcl->decl.isextern = 1;
+    htput(globls, dcl, asmname(dcl->decl.name));
+
+    abortoob = mkexpr(Zloc, Ovar, name, NULL);
+    abortoob->expr.type = ty;
+    abortoob->expr.did = dcl->decl.did;
+    abortoob->expr.isconst = 1;
+}
+
+static void printmem(FILE *fd, Loc *l, char spec)
+{
+    if (l->type == Locmem) {
+        if (l->mem.constdisp)
+            fprintf(fd, "%ld", l->mem.constdisp);
+    } else {
+        if (l->mem.lbldisp)
+            fprintf(fd, "%s", l->mem.lbldisp);
+    }
+    if (l->mem.base && l->mem.base->reg.colour != Rrip) {
+        fprintf(fd, "(");
+        locprint(fd, l->mem.base, 'r');
+        if (l->mem.idx) {
+            fprintf(fd, ",");
+            locprint(fd, l->mem.idx, 'r');
+        }
+        if (l->mem.scale > 1)
+            fprintf(fd, ",%d", l->mem.scale);
+        if (l->mem.base)
+            fprintf(fd, ")");
+    } else if (l->type != Locmeml) {
+        die("Only locmeml can have unspecified base reg");
+    }
+}
+
+static void locprint(FILE *fd, Loc *l, char spec)
+{
+    spec = tolower(spec);
+    assert(l->mode);
+    switch (l->type) {
+        case Loclitl:
+            assert(spec == 'i' || spec == 'x' || spec == 'u');
+            fprintf(fd, "$%s", l->lbl);
+            break;
+        case Loclbl:
+            assert(spec == 'm' || spec == 'v' || spec == 'x');
+            fprintf(fd, "%s", l->lbl);
+            break;
+        case Locreg:
+            assert((spec == 'r' && isintmode(l->mode)) || 
+                   (spec == 'f' && isfloatmode(l->mode)) ||
+                   spec == 'v' ||
+                   spec == 'x' ||
+                   spec == 'u');
+            if (l->reg.colour == Rnone)
+                fprintf(fd, "%%P.%zd%s", l->reg.id, modenames[l->mode]);
+            else
+                fprintf(fd, "%s", regnames[l->reg.colour]);
+            break;
+        case Locmem:
+        case Locmeml:
+            assert(spec == 'm' || spec == 'v' || spec == 'x');
+            printmem(fd, l, spec);
+            break;
+        case Loclit:
+            assert(spec == 'i' || spec == 'x' || spec == 'u');
+            fprintf(fd, "$%ld", l->lit);
+            break;
+        case Locnone:
+            die("Bad location in locprint()");
+            break;
+    }
+}
+
+static int issubreg(Loc *a, Loc *b)
+{
+    return rclass(a) == rclass(b) && a->mode != b->mode;
+}
+
+static void iprintf(FILE *fd, Insn *insn)
+{
+    char *p;
+    int i;
+    int modeidx;
+
+    /* x64 has a quirk; it has no movzlq because mov zero extends. This
+     * means that we need to do a movl when we really want a movzlq. Since
+     * we don't know the name of the reg to use, we need to sub it in when
+     * writing... */
+    switch (insn->op) {
+        case Imovzx:
+            if (insn->args[0]->mode == ModeL && insn->args[1]->mode == ModeQ) {
+                if (insn->args[1]->reg.colour) {
+                    insn->op = Imov;
+                    insn->args[1] = coreg(insn->args[1]->reg.colour, ModeL);
+                }
+            }
+            break;
+        case Imovs:
+            if (insn->args[0]->reg.colour == Rnone || insn->args[1]->reg.colour == Rnone)
+                break;
+            /* moving a reg to itself is dumb. */
+            if (insn->args[0]->reg.colour == insn->args[1]->reg.colour)
+                return;
+            break;
+        case Imov:
+            assert(!isfloatmode(insn->args[0]->mode));
+            if (insn->args[0]->type != Locreg || insn->args[1]->type != Locreg)
+                break;
+            if (insn->args[0]->reg.colour == Rnone || insn->args[1]->reg.colour == Rnone)
+                break;
+            /* if one reg is a subreg of another, we can just use the right
+             * mode to move between them. */
+            if (issubreg(insn->args[0], insn->args[1]))
+                insn->args[0] = coreg(insn->args[0]->reg.colour, insn->args[1]->mode);
+            /* moving a reg to itself is dumb. */
+            if (insn->args[0]->reg.colour == insn->args[1]->reg.colour)
+                return;
+            break;
+        default:
+            break;
+    }
+    p = insnfmt[insn->op];
+    i = 0;
+    modeidx = 0;
+    for (; *p; p++) {
+        if (*p !=  '%') {
+            fputc(*p, fd);
+            continue;
+        }
+
+        /* %-formating */
+        p++;
+        switch (*p) {
+            case '\0':
+                goto done; /* skip the final p++ */
+            case 'r': /* int register */
+            case 'f': /* float register */
+            case 'm': /* memory */
+            case 'i': /* imm */
+            case 'v': /* reg/mem */
+            case 'u': /* reg/imm */
+            case 'x': /* reg/mem/imm */
+                locprint(fd, insn->args[i], *p);
+                i++;
+                break;
+            case 'R': /* int register */
+            case 'F': /* float register */
+            case 'M': /* memory */
+            case 'I': /* imm */
+            case 'V': /* reg/mem */
+            case 'U': /* reg/imm */
+            case 'X': /* reg/mem/imm */
+                locprint(fd, insn->args[i], *p);
+                i++;
+                break;
+            case 't':
+            case 'T':
+            default:
+                /* the  asm description uses 1-based indexing, so that 0
+                 * can be used as a sentinel. */
+                if (isdigit(*p))
+                    modeidx = strtol(p, &p, 10) - 1;
+
+                if (*p == 'T')
+                    fputs(modenames[insn->args[modeidx]->mode], fd);
+                else
+                    die("Invalid %%-specifier '%c'", *p);
+                break;
+        }
+    }
+done:
+    return;
+}
+
+
+static size_t writebytes(FILE *fd, char *name, size_t off, char *p, size_t sz)
+{
+    size_t i, len;
+
+    for (i = 0; i < sz; i++) {
+        len = min(i, 8);
+        if (i % 8 == 0)
+            fprintf(fd, "DATA %s+%zd(SB)/%zd,$\"", name, off + i, len);
+        if (p[i] == '"' || p[i] == '\\')
+            fprintf(fd, "\\");
+        if (isprint(p[i]))
+            fprintf(fd, "%c", p[i]);
+        else
+            fprintf(fd, "\\%03o", (uint8_t)p[i] & 0xff);
+        /* line wrapping for readability */
+        if (i % 8 == 7 || i == sz - 1)
+            fprintf(fd, "\"\n");
+    }
+
+    return sz;
+}
+
+static size_t writelit(FILE *fd, char *name, size_t off, Htab *strtab, Node *v, Type *ty)
+{
+    char buf[128];
+    char *lbl;
+    size_t sz;
+    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:
+            fprintf(fd, "DATA %s+%zd(SB)/%zd,$%lld\n", name, off, sz, v->lit.intval);
+            break;
+        case Lbool:
+            fprintf(fd, "DATA %s+%zd(SB)/%zd,$%d\n", name, off, sz, v->lit.boolval);
+            break;
+        case Lchr:
+            fprintf(fd, "DATA %s+%zd(SB)/%zd,$%d\n", name, off, sz, v->lit.chrval);
+            break;
+        case Lflt:
+            if (tybase(v->lit.type)->type == Tyflt32) {
+                u.fv = v->lit.fltval;
+                fprintf(fd, "DATA %s+%zd(SB)/%zd, $0x%llx\n", name, off, sz, (vlong)u.lv);
+            } else if (tybase(v->lit.type)->type == Tyflt64) {
+                u.dv = v->lit.fltval;
+                fprintf(fd, "DATA %s+%zd(SB)/%zd, $0x%llx\n", name, off, sz, (vlong)u.qv);
+            }
+            break;
+        case Lstr:
+           if (hthas(strtab, &v->lit.strval)) {
+               lbl = htget(strtab, &v->lit.strval);
+           } else {
+               lbl = genlblstr(buf, sizeof buf);
+               htput(strtab, &v->lit.strval, strdup(lbl));
+           }
+           fprintf(fd, "DATA %s+%zd(SB)/8,%s<>+0(SB)\n", name, off, lbl);
+           fprintf(fd, "DATA %s+%zd(SB)/8,$%zd\n", name, off+8, 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 writepad(FILE *fd, size_t sz)
+{
+    assert((ssize_t)sz >= 0);
+    if (sz > 0)
+        fprintf(fd, "\t.fill %zd,1,0\n", sz);
+    return sz;
+}
+
+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 size_t writeslice(FILE *fd, 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);
+    fprintf(fd, "\t.quad %s + (%zd*%zd)\n", lbl, loval, sz);
+    fprintf(fd, "\t.quad %zd\n", (hival - loval));
+    return size(n);
+}
+
+static size_t writestruct(FILE *fd, char *name, size_t off, Htab *globls, Htab *strtab, Node *n)
+{
+    Type *t;
+    Node **dcl;
+    int found;
+    size_t i, j;
+    size_t pad, start, end;
+    size_t ndcl;
+
+    start = off;
+    t = tybase(exprtype(n));
+    assert(t->type == Tystruct);
+    dcl = t->sdecls;
+    ndcl = t->nmemb;
+    for (i = 0; i < ndcl; i++) {
+        pad = alignto(off, decltype(dcl[i]));
+        off += writepad(fd, pad - off);
+        found = 0;
+        for (j = 0; j < n->expr.nargs; j++)
+            if (!strcmp(namestr(n->expr.args[j]->expr.idx), declname(dcl[i]))) {
+                found = 1;
+                off += writeblob(fd, name, off, globls, strtab, n->expr.args[j]);
+            }
+        if (!found)
+            off += writepad(fd, size(dcl[i]));
+    }
+    end = alignto(off, t);
+    off += writepad(fd, end - off);
+    return off - start;
+}
+static size_t writeblob(FILE *fd, char *name, size_t off, Htab *globls, Htab *strtab, Node *n)
+{
+    size_t i, sz;
+
+    switch(exprop(n)) {
+        case Otup:
+        case Oarr:
+            sz = 0;
+            for (i = 0; i < n->expr.nargs; i++)
+                sz += writeblob(fd, name, off, globls, strtab, n->expr.args[i]);
+            break;
+        case Ostruct:
+            sz = writestruct(fd, name, off, globls, strtab, n);
+            break;
+        case Olit:
+            sz = writelit(fd, name, off, strtab, n->expr.args[0], exprtype(n));
+            break;
+        case Oslice:
+            sz = writeslice(fd, globls, strtab, n);
+            break;
+        default:
+            dump(n, stdout);
+            die("Nonliteral initializer for global");
+            break;
+    }
+    return sz;
+}
+
+static void genstrings(FILE *fd, Htab *strtab)
+{
+    void **k;
+    Str *s;
+    size_t i, nk;
+
+    k = htkeys(strtab, &nk);
+    for (i = 0; i < nk; i++) {
+        s = k[i];
+        writebytes(fd, htget(strtab, k[i]), 0, s->buf, s->len);
+    }
+}
+
+
+static void writeasm(FILE *fd, Isel *s, Func *fn)
+{
+    size_t i, j;
+    char *hidden;
+
+    hidden = "<>";
+    if (fn->isexport || streq(fn->name, Symprefix "main"))
+        hidden = "";
+    fprintf(fd, "TEXT %s%s+0(SB),$%zd\n", fn->name, hidden, fn->stksz);
+    for (j = 0; j < s->cfg->nbb; j++) {
+        if (!s->bb[j])
+            continue;
+        for (i = 0; i < s->bb[j]->nlbls; i++)
+            fprintf(fd, "%s:\n", s->bb[j]->lbls[i]);
+        for (i = 0; i < s->bb[j]->ni; i++)
+            iprintf(fd, s->bb[j]->il[i]);
+    }
+}
+
+static void genblob(FILE *fd, Node *blob, Htab *globls, Htab *strtab)
+{
+    char *lbl;
+
+    /* lits and such also get wrapped in decls */
+    assert(blob->type == Ndecl);
+
+    lbl = htget(globls, blob);
+    if (blob->decl.vis != Visintern)
+        fprintf(fd, "GLOBL %s,%zd\n", lbl, size(blob));
+    if (blob->decl.init)
+        writeblob(fd, lbl, 0, globls, strtab, blob->decl.init);
+    else
+        writepad(fd, size(blob));
+}
+
+/* genfunc requires all nodes in 'nl' to map cleanly to operations that are
+ * natively supported, as promised in the output of reduce().  No 64-bit
+ * operations on x32, no structures, and so on. */
+static void genfunc(FILE *fd, Func *fn, Htab *globls, Htab *strtab)
+{
+    Isel is = {0,};
+
+    is.reglocs = mkht(varhash, vareq);
+    is.stkoff = fn->stkoff;
+    is.globls = globls;
+    is.ret = fn->ret;
+    is.cfg = fn->cfg;
+
+    selfunc(&is, fn, globls, strtab);
+    if (debugopt['i'])
+        writeasm(stdout, &is, fn);
+    writeasm(fd, &is, fn);
+}
+
+void genp9(Node *file, char *out)
+{
+    Htab *globls, *strtab;
+    Node *n, **blob;
+    Func **fn;
+    size_t nfn, nblob;
+    size_t i;
+    FILE *fd;
+
+    /* ensure that all physical registers have a loc created before any
+     * other locs, so that locmap[Physreg] maps to the Loc for the physreg
+     * in question */
+    for (i = 0; i < Nreg; i++)
+        locphysreg(i);
+
+    fn = NULL;
+    nfn = 0;
+    blob = NULL;
+    nblob = 0;
+    globls = mkht(varhash, vareq);
+    initconsts(globls);
+
+    /* We need to define all global variables before use */
+    fillglobls(file->file.globls, globls);
+
+    pushstab(file->file.globls);
+    for (i = 0; i < file->file.nstmts; i++) {
+        n = file->file.stmts[i];
+        switch (n->type) {
+            case Nuse: /* nothing to do */ 
+            case Nimpl:
+                break;
+            case Ndecl:
+                simpglobl(n, globls, &fn, &nfn, &blob, &nblob);
+                break;
+            default:
+                die("Bad node %s in toplevel", nodestr(n->type));
+                break;
+        }
+    }
+    popstab();
+
+    fd = fopen(out, "w");
+    if (!fd)
+        die("Couldn't open fd %s", out);
+
+    strtab = mkht(strlithash, strliteq);
+    for (i = 0; i < nblob; i++)
+        genblob(fd, blob[i], globls, strtab);
+    for (i = 0; i < nfn; i++)
+        genfunc(fd, fn[i], globls, strtab);
+    genstrings(fd, strtab);
+    fclose(fd);
+}
--- a/6/insns.def
+++ b/6/insns.def
@@ -28,7 +28,7 @@
 /* Note, the mov instruction is specified in an overly general manner. */
 Insn(Imov,      
     "\tmov%t %x,%x\n",              
-    "\tMOV%t %X,%X\n",
+    "\tMOV%T %X,%X\n",
     Use(.l={1}),
     Def(.l={2}))
 Insn(Imovt,      
@@ -38,7 +38,7 @@
     Def(.l={2}))
 Insn(Imovzx,    
     "\tmovz%1t%2t %x,%x\n",         
-    "\tMOVZ%1t%2t %X,%X\n",
+    "\tMOVZ%1T%2T %X,%X\n",
     Use(.l={1}),
     Def(.l={2}))
 Insn(Imovsx,    
@@ -347,9 +347,15 @@
     Use(.r={Rrax,Rxmm0d}),
     Def(None))
 
-/* not really an insn... */
+/* not actually insns */
 Insn(Ilbl,      
     "%v:\n",                        
     "%V:\n",
+    Use(None),
+    Def(None))
+
+Insn(Icomment,      
+    "\t#%v\n",                        
+    "\t//%v:\n",
     Use(None),
     Def(None))
--- a/6/isel.c
+++ b/6/isel.c
@@ -150,7 +150,7 @@
     va_end(ap);
     if (debugopt['i']) {
         printf("GEN[uid=%zd] ", i->uid);
-        iprintf(stdout, i);
+        dbgiprintf(stdout, i);
     }
     lappend(&s->curbb->il, &s->curbb->ni, i);
 }
@@ -868,9 +868,9 @@
         for (i = 0; i < bb->nnl; i++) {
             /* put in a comment that says where this line comes from */
             n = bb->nl[i];
-            snprintf(buf, sizeof buf, "\n\t# bb = %ld, bbidx = %ld, %s:%d",
+            snprintf(buf, sizeof buf, "bb = %ld, bbidx = %ld, %s:%d",
                      j, i, file->file.files[n->loc.file], n->loc.line);
-            g(is, Ilbl, locstrlbl(buf), NULL);
+            g(is, Icomment, locstrlbl(buf), NULL);
             isel(is, fn->cfg->bb[j]->nl[i]);
         }
     }
--- a/6/locs.c
+++ b/6/locs.c
@@ -16,52 +16,9 @@
 #include "../config.h"
 
 Mode regmodes[] = {
-#define Reg(r, name, mode) mode,
+#define Reg(r, gasname, p9name, mode) mode,
 #include "regs.def"
 #undef Reg
-};
-
-char *regnames[] = {
-#define Reg(r, name, mode) name,
-#include "regs.def"
-#undef Reg
-};
-
-size_t modesize[Nmode] = {
-    [ModeNone]  = 0,
-    [ModeB]     = 1,
-    [ModeW]     = 2,
-    [ModeL]     = 4,
-    [ModeQ]     = 8,
-    [ModeF]     = 4,
-    [ModeD]     = 8,
-};
-    
-
-const Reg reginterferes[Nreg][Nmode + 1] = {
-    /* byte */
-    [Ral] = {Ral, Rax, Reax},
-    [Rcl] = {Rcl, Rcx, Recx},
-    [Rdl] = {Rdl, Rdx, Redx},
-    [Rbl] = {Rbl, Rbx, Rebx},
-
-    /* word */
-    [Rax] = {Ral, Rax, Reax},
-    [Rcx] = {Rcl, Rcx, Recx},
-    [Rdx] = {Rdl, Rdx, Redx},
-    [Rbx] = {Rbl, Rbx, Rebx},
-    [Rsi] = {Rsi, Resi},
-    [Rdi] = {Rdi, Redi},
-
-    /* dword */
-    [Reax] = {Ral, Rax, Reax},
-    [Recx] = {Rcl, Rcx, Recx},
-    [Redx] = {Rdl, Rdx, Redx},
-    [Rebx] = {Rbl, Rbx, Rebx},
-    [Resi] = {Rsi, Resi},
-    [Redi] = {Rdi, Redi},
-    [Resp] = {Resp},
-    [Rebp] = {Rebp},
 };
 
 int isintmode(Mode m)
--- a/6/main.c
+++ b/6/main.c
@@ -46,7 +46,7 @@
     printf("\t-S\tGenerate assembly instead of object code\n");
 }
 
-static void assem(char *asmsrc, char *path)
+static void assemble(char *asmsrc, char *path)
 {
     char *asmcmd[] = Asmcmd;
     char objfile[1024];
@@ -126,9 +126,11 @@
     char buf[1024];
     Stab *globls;
     Optctx ctx;
+    Asmsyntax asmsyntax;
     size_t i;
 
-    optinit(&ctx, "d:hSo:I:", argv, argc);
+    optinit(&ctx, "d:hSo:I:9G", argv, argc);
+    asmsyntax = Defaultasm;
     while (!optdone(&ctx)) {
         switch (optnext(&ctx)) {
             case 'o':
@@ -147,6 +149,12 @@
                 while (ctx.optarg && *ctx.optarg)
                     debugopt[*ctx.optarg++ & 0x7f]++;
                 break;
+            case '9':
+                asmsyntax = Plan9;
+                break;
+            case 'G':
+                asmsyntax = Gnugas;
+                break;
             case 'I':
                 lappend(&incpaths, &nincpaths, ctx.optarg);
                 break;
@@ -180,8 +188,8 @@
         } else {
             gentemp(buf, sizeof buf, ctx.args[i], ".s");
         }
-        gen(file, buf);
-        assem(buf, ctx.args[i]);
+        gen(asmsyntax, file, buf);
+        assemble(buf, ctx.args[i]);
         genuse(ctx.args[i]);
     }
 
--- a/6/ra.c
+++ b/6/ra.c
@@ -118,6 +118,17 @@
     [Rxmm15f] = 31,  [Rxmm15d] = 31,
 };
 
+size_t modesize[Nmode] = {
+    [ModeNone]  = 0,
+    [ModeB]     = 1,
+    [ModeW]     = 2,
+    [ModeL]     = 4,
+    [ModeQ]     = 8,
+    [ModeF]     = 4,
+    [ModeD]     = 8,
+};
+    
+
 static int _K[Nclass] = {
     [Classbad] = 0,
     [Classint] = 14,
@@ -943,11 +954,6 @@
         found = 0;
         for (i = 0; i < Northogonal; i++) {
             if (regmap[i][n->mode] && !taken[i]) {
-                if (debugopt['r']) {
-                    fprintf(stdout, "\tselecting ");
-                    locprint(stdout, n, 'x');
-                    fprintf(stdout, " = %s\n", regnames[regmap[i][n->mode]]);
-                }
                 n->reg.colour = regmap[i][n->mode];
                 found = 1;
                 break;
@@ -1105,9 +1111,9 @@
                 lappend(&new, &nnew, insn);
                 if (debugopt['r']) {
                     printf("loading ");
-                    locprint(stdout, locmap[use[i].oldreg], 'x');
+                    dbglocprint(stdout, locmap[use[i].oldreg], 'x');
                     printf(" -> ");
-                    locprint(stdout, use[i].newreg, 'x');
+                    dbglocprint(stdout, use[i].newreg, 'x');
                     printf("\n");
                 }
             }
@@ -1122,9 +1128,9 @@
                 lappend(&new, &nnew, insn);
                 if (debugopt['r']) {
                     printf("storing ");
-                    locprint(stdout, locmap[def[i].oldreg], 'x');
+                    dbglocprint(stdout, locmap[def[i].oldreg], 'x');
                     printf(" -> ");
-                    locprint(stdout, def[i].newreg, 'x');
+                    dbglocprint(stdout, def[i].newreg, 'x');
                     printf("\n");
                 }
             }
@@ -1143,7 +1149,7 @@
     s->stksz->lit = align(s->stksz->lit, modesize[l->mode]);
     if (debugopt['r']) {
         printf("spill ");
-        locprint(stdout, l, 'x');
+        dbglocprint(stdout, l, 'x');
         printf(" to %zd(%%rbp)\n", s->stksz->lit);
     }
     htput(s->spillslots, itop(l->reg.id), itop(s->stksz->lit));
@@ -1265,7 +1271,7 @@
     fprintf(fd, "%s = [", name);
     for (i = 0; i < nwl; i++) {
         fprintf(fd, "%s", sep);
-        locprint(fd, wl[i], 'x');
+        dbglocprint(fd, wl[i], 'x');
         fprintf(fd, "(%zd)", wl[i]->reg.id);
         sep = ",";
     }
@@ -1296,7 +1302,7 @@
     for (i = 0; i < bsmax(s); i++) {
         if (bshas(s, i)) {
             fprintf(fd, "%s", sep);
-            locprint(fd, locmap[i], 'x');
+            dbglocprint(fd, locmap[i], 'x');
             sep = ",";
         }
     }
@@ -1306,9 +1312,9 @@
 static void printedge(FILE *fd, char *msg, size_t a, size_t b)
 {
     fprintf(fd, "\t%s ", msg);
-    locprint(fd, locmap[a], 'x');
+    dbglocprint(fd, locmap[a], 'x');
     fprintf(fd, " -- ");
-    locprint(fd, locmap[b], 'x');
+    dbglocprint(fd, locmap[b], 'x');
     fprintf(fd, "\n");
 }
 
@@ -1360,7 +1366,7 @@
         fprintf(fd, "Liveout: ");
         locsetprint(fd, bb->liveout);
         for (i = 0; i < bb->ni; i++)
-            iprintf(fd, bb->il[i]);
+            dbgiprintf(fd, bb->il[i]);
     }
     fprintf(fd, "ENDASM -------- \n");
 }
--- a/6/regs.def
+++ b/6/regs.def
@@ -1,117 +1,117 @@
-Reg(Rnone, "%NOREG", ModeB)
+Reg(Rnone, "%NOREG", "NOREG", ModeB)
 /* byte regs */
-Reg(Ral, "%al", ModeB)
-Reg(Rcl, "%cl", ModeB)
-Reg(Rdl, "%dl", ModeB)
-Reg(Rbl, "%bl", ModeB)
-Reg(Rsil, "%sil", ModeB)
-Reg(Rdil, "%dil", ModeB)
-Reg(Rspl, "%spl", ModeB)
-Reg(Rbpl, "%bpl", ModeB)
-Reg(Rr8b, "%r8b", ModeB)
-Reg(Rr9b, "%r9b", ModeB)
-Reg(Rr10b, "%r10b", ModeB)
-Reg(Rr11b, "%r11b", ModeB)
-Reg(Rr12b, "%r12b", ModeB)
-Reg(Rr13b, "%r13b", ModeB)
-Reg(Rr14b, "%r14b", ModeB)
-Reg(Rr15b, "%r15b", ModeB)
+Reg(Ral,   "%al", "AL", ModeB)
+Reg(Rcl,   "%cl", "CL", ModeB)
+Reg(Rdl,   "%dl", "DL", ModeB)
+Reg(Rbl,   "%bl", "BL", ModeB)
+Reg(Rsil,  "%sil", "SIL", ModeB)
+Reg(Rdil,  "%dil", "DIL", ModeB)
+Reg(Rspl,  "%spl", "SPL", ModeB)
+Reg(Rbpl,  "%bpl", "BPL", ModeB)
+Reg(Rr8b,  "%r8b", "BPL", ModeB)
+Reg(Rr9b,  "%r9b", "BPL", ModeB)
+Reg(Rr10b, "%r10b", "R10", ModeB)
+Reg(Rr11b, "%r11b", "R11", ModeB)
+Reg(Rr12b, "%r12b", "R12", ModeB)
+Reg(Rr13b, "%r13b", "R13", ModeB)
+Reg(Rr14b, "%r14b", "R14", ModeB)
+Reg(Rr15b, "%r15b", "R15", ModeB)
 
 /* high byte regs. We *NEVER* allocate these */
-Reg(Rah, "%ah", ModeB)
-Reg(Rch, "%ch", ModeB)
-Reg(Rdh, "%dh", ModeB)
-Reg(Rbh, "%bh", ModeB)
+Reg(Rah,   "%ah", "AH", ModeB)
+Reg(Rch,   "%ch", "CH", ModeB)
+Reg(Rdh,   "%dh", "DH", ModeB)
+Reg(Rbh,   "%bh", "BH", ModeB)
 
 /* short regs */
-Reg(Rax, "%ax", ModeW)
-Reg(Rbx, "%bx", ModeW)
-Reg(Rcx, "%cx", ModeW)
-Reg(Rdx, "%dx", ModeW)
-Reg(Rsi, "%si", ModeW)
-Reg(Rdi, "%di", ModeW)
-Reg(Rsp, "%sp", ModeW)
-Reg(Rbp, "%bp", ModeW)
-Reg(Rr8w, "%r8w", ModeW)
-Reg(Rr9w, "%r9w", ModeW)
-Reg(Rr10w, "%r10w", ModeW)
-Reg(Rr11w, "%r11w", ModeW)
-Reg(Rr12w, "%r12w", ModeW)
-Reg(Rr13w, "%r13w", ModeW)
-Reg(Rr14w, "%r14w", ModeW)
-Reg(Rr15w, "%r15w", ModeW)
+Reg(Rax,   "%ax",   "AX",  ModeW)
+Reg(Rbx,   "%bx",   "BX",  ModeW)
+Reg(Rcx,   "%cx",   "CX",  ModeW)
+Reg(Rdx,   "%dx",   "DX",  ModeW)
+Reg(Rsi,   "%si",   "SI",  ModeW)
+Reg(Rdi,   "%di",   "DI",  ModeW)
+Reg(Rsp,   "%sp",   "SP",  ModeW)
+Reg(Rbp,   "%bp",   "BP",  ModeW)
+Reg(Rr8w,  "%r8w",  "R8",  ModeW)
+Reg(Rr9w,  "%r9w",  "R9",  ModeW)
+Reg(Rr10w, "%r10w", "R10", ModeW)
+Reg(Rr11w, "%r11w", "R11", ModeW)
+Reg(Rr12w, "%r12w", "R12", ModeW)
+Reg(Rr13w, "%r13w", "R13", ModeW)
+Reg(Rr14w, "%r14w", "R14", ModeW)
+Reg(Rr15w, "%r15w", "R15", ModeW)
 
 
 /* long regs */
-Reg(Reax, "%eax", ModeL)
-Reg(Recx, "%ecx", ModeL)
-Reg(Redx, "%edx", ModeL)
-Reg(Rebx, "%ebx", ModeL)
-Reg(Resi, "%esi", ModeL)
-Reg(Redi, "%edi", ModeL)
-Reg(Resp, "%esp", ModeL)
-Reg(Rebp, "%ebp", ModeL)
-Reg(Rr8d, "%r8d", ModeL)
-Reg(Rr9d, "%r9d", ModeL)
-Reg(Rr10d, "%r10d", ModeL)
-Reg(Rr11d, "%r11d", ModeL)
-Reg(Rr12d, "%r12d", ModeL)
-Reg(Rr13d, "%r13d", ModeL)
-Reg(Rr14d, "%r14d", ModeL)
-Reg(Rr15d, "%r15d", ModeL)
+Reg(Reax,  "%eax",  "AX",  ModeL)
+Reg(Recx,  "%ecx",  "BX",  ModeL)
+Reg(Redx,  "%edx",  "CX",  ModeL)
+Reg(Rebx,  "%ebx",  "DX",  ModeL)
+Reg(Resi,  "%esi",  "SI",  ModeL)
+Reg(Redi,  "%edi",  "DI",  ModeL)
+Reg(Resp,  "%esp",  "SP",  ModeL)
+Reg(Rebp,  "%ebp",  "BP",  ModeL)
+Reg(Rr8d,  "%r8d",  "R8",  ModeL)
+Reg(Rr9d,  "%r9d",  "R9",  ModeL)
+Reg(Rr10d, "%r10d", "R10", ModeL)
+Reg(Rr11d, "%r11d", "R11", ModeL)
+Reg(Rr12d, "%r12d", "R12", ModeL)
+Reg(Rr13d, "%r13d", "R13", ModeL)
+Reg(Rr14d, "%r14d", "R14", ModeL)
+Reg(Rr15d, "%r15d", "R15", ModeL)
 
 /* quad regs */
-Reg(Rrax, "%rax", ModeQ)
-Reg(Rrcx, "%rcx", ModeQ)
-Reg(Rrdx, "%rdx", ModeQ)
-Reg(Rrbx, "%rbx", ModeQ)
-Reg(Rrsi, "%rsi", ModeQ)
-Reg(Rrdi, "%rdi", ModeQ)
-Reg(Rr8, "%r8", ModeQ)
-Reg(Rr9, "%r9", ModeQ)
-Reg(Rr10, "%r10", ModeQ)
-Reg(Rr11, "%r11", ModeQ)
-Reg(Rr12, "%r12", ModeQ)
-Reg(Rr13, "%r13", ModeQ)
-Reg(Rr14, "%r14", ModeQ)
-Reg(Rr15, "%r15", ModeQ)
+Reg(Rrax, "%rax", "AX",  ModeQ)
+Reg(Rrcx, "%rcx", "BX",  ModeQ)
+Reg(Rrdx, "%rdx", "CX",  ModeQ)
+Reg(Rrbx, "%rbx", "DX",  ModeQ)
+Reg(Rrsi, "%rsi", "SI",  ModeQ)
+Reg(Rrdi, "%rdi", "DI",  ModeQ)
+Reg(Rrsp, "%rsp", "SP",  ModeQ)
+Reg(Rrbp, "%rbp", "BP",  ModeQ)
+Reg(Rr8,  "%r8",  "R8",  ModeQ)
+Reg(Rr9,  "%r9",  "R9",  ModeQ)
+Reg(Rr10, "%r10", "R10", ModeQ)
+Reg(Rr11, "%r11", "R11", ModeQ)
+Reg(Rr12, "%r12", "R12", ModeQ)
+Reg(Rr13, "%r13", "R13", ModeQ)
+Reg(Rr14, "%r14", "R14", ModeQ)
+Reg(Rr15, "%r15", "R15", ModeQ)
 
 /* floating point registers */
-Reg(Rxmm0f, "%xmm0", ModeF)
-Reg(Rxmm1f, "%xmm1", ModeF)
-Reg(Rxmm2f, "%xmm2", ModeF)
-Reg(Rxmm3f, "%xmm3", ModeF)
-Reg(Rxmm4f, "%xmm4", ModeF)
-Reg(Rxmm5f, "%xmm5", ModeF)
-Reg(Rxmm6f, "%xmm6", ModeF)
-Reg(Rxmm7f, "%xmm7", ModeF)
-Reg(Rxmm8f, "%xmm8", ModeF)
-Reg(Rxmm9f, "%xmm9", ModeF)
-Reg(Rxmm10f, "%xmm10", ModeF)
-Reg(Rxmm11f, "%xmm11", ModeF)
-Reg(Rxmm12f, "%xmm12", ModeF)
-Reg(Rxmm13f, "%xmm13", ModeF)
-Reg(Rxmm14f, "%xmm14", ModeF)
-Reg(Rxmm15f, "%xmm15", ModeF)
+Reg(Rxmm0f,  "%xmm0",  "MM0",  ModeF)
+Reg(Rxmm1f,  "%xmm1",  "MM1",  ModeF)
+Reg(Rxmm2f,  "%xmm2",  "MM2",  ModeF)
+Reg(Rxmm3f,  "%xmm3",  "MM3",  ModeF)
+Reg(Rxmm4f,  "%xmm4",  "MM4",  ModeF)
+Reg(Rxmm5f,  "%xmm5",  "MM5",  ModeF)
+Reg(Rxmm6f,  "%xmm6",  "MM6",  ModeF)
+Reg(Rxmm7f,  "%xmm7",  "MM7",  ModeF)
+Reg(Rxmm8f,  "%xmm8",  "MM8",  ModeF)
+Reg(Rxmm9f,  "%xmm9",  "MM9",  ModeF)
+Reg(Rxmm10f, "%xmm10", "MM10", ModeF)
+Reg(Rxmm11f, "%xmm11", "MM11", ModeF)
+Reg(Rxmm12f, "%xmm12", "MM12", ModeF)
+Reg(Rxmm13f, "%xmm13", "MM13", ModeF)
+Reg(Rxmm14f, "%xmm14", "MM14", ModeF)
+Reg(Rxmm15f, "%xmm15", "MM15", ModeF)
 
 /* double precision floating point registers */
-Reg(Rxmm0d, "%xmm0", ModeD)
-Reg(Rxmm1d, "%xmm1", ModeD)
-Reg(Rxmm2d, "%xmm2", ModeD)
-Reg(Rxmm3d, "%xmm3", ModeD)
-Reg(Rxmm4d, "%xmm4", ModeD)
-Reg(Rxmm5d, "%xmm5", ModeD)
-Reg(Rxmm6d, "%xmm6", ModeD)
-Reg(Rxmm7d, "%xmm7", ModeD)
-Reg(Rxmm8d, "%xmm8", ModeD)
-Reg(Rxmm9d, "%xmm9", ModeD)
-Reg(Rxmm10d, "%xmm10", ModeD)
-Reg(Rxmm11d, "%xmm11", ModeD)
-Reg(Rxmm12d, "%xmm12", ModeD)
-Reg(Rxmm13d, "%xmm13", ModeD)
-Reg(Rxmm14d, "%xmm14", ModeD)
-Reg(Rxmm15d, "%xmm15", ModeD)
+Reg(Rxmm0d,  "%xmm0",  "MM0",  ModeD)
+Reg(Rxmm1d,  "%xmm1",  "MM1",  ModeD)
+Reg(Rxmm2d,  "%xmm2",  "MM2",  ModeD)
+Reg(Rxmm3d,  "%xmm3",  "MM3",  ModeD)
+Reg(Rxmm4d,  "%xmm4",  "MM4",  ModeD)
+Reg(Rxmm5d,  "%xmm5",  "MM5",  ModeD)
+Reg(Rxmm6d,  "%xmm6",  "MM6",  ModeD)
+Reg(Rxmm7d,  "%xmm7",  "MM7",  ModeD)
+Reg(Rxmm8d,  "%xmm8",  "MM8",  ModeD)
+Reg(Rxmm9d,  "%xmm9",  "MM9",  ModeD)
+Reg(Rxmm10d, "%xmm10", "MM10", ModeD)
+Reg(Rxmm11d, "%xmm11", "MM11", ModeD)
+Reg(Rxmm12d, "%xmm12", "MM12", ModeD)
+Reg(Rxmm13d, "%xmm13", "MM13", ModeD)
+Reg(Rxmm14d, "%xmm14", "MM14", ModeD)
+Reg(Rxmm15d, "%xmm15", "MM15", ModeD)
 
-Reg(Rrip, "%rip", ModeQ)
-Reg(Rrsp, "%rsp", ModeQ)
-Reg(Rrbp, "%rbp", ModeQ)
+Reg(Rrip, "%rip", "PC", ModeQ)
--- a/configure
+++ b/configure
@@ -39,19 +39,19 @@
     *Linux*)
         echo '#define Asmcmd {"as", "-g", "-o", NULL}' >> config.h
         echo '#define Symprefix ""' >> config.h
-        echo '#define insnfmt gasinsnfmt' >> config.h
+        echo '#define Defaultasm Gnugas' >> config.h
         echo 'export SYS=linux' >> config.mk
         ;;
     *Darwin*)
         echo '#define Asmcmd {"as", "-g", "-o", NULL}' >> config.h
         echo '#define Symprefix "_"' >> config.h
-        echo '#define insnfmt gasinsnfmt' >> config.h
+        echo '#define Defaultasm Gnugas' >> config.h
         echo 'export SYS=osx' >> config.mk
         ;;
     *FreeBSD*)
         echo '#define Asmcmd {"as", "-g", "-o", NULL}' >> config.h
         echo '#define Symprefix ""' >> config.h
-        echo '#define insnfmt gasinsnfmt' >> config.h
+        echo '#define Defaultasm Gnugas' >> config.h
         echo 'export SYS=freebsd' >> config.mk
         ;;
     *)