shithub: mc

Download patch

ref: afbbc54292c6e52787461058786c80009723a24c
parent: 7f63840cfaa3640e76d6ac0688a19ba52a68764a
author: Ori Bernstein <[email protected]>
date: Fri Jun 29 10:38:49 EDT 2012

Rename file.

--- a/8/Makefile
+++ b/8/Makefile
@@ -3,7 +3,7 @@
     locs.o \
     main.o \
     ra.o \
-    reduce.o \
+    simp.o \
 
 DEPS=../parse/libparse.a ../opt/libopt.a
 
--- a/8/reduce.c
+++ /dev/null
@@ -1,1035 +1,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.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 "opt.h"
-#include "asm.h"
-
-#include "platform.h" /* HACK. We need some platform specific code gen behavior. *sigh.* */
-
-/* takes a list of nodes, and reduces it (and it's subnodes) to a list
- * following these constraints:
- *      - All nodes are expression nodes
- *      - Nodes with side effects are root nodes
- *      - All nodes operate on machine-primitive types and tuples
- */
-typedef struct Simp Simp;
-struct Simp {
-    int isglobl;
-
-    Node **stmts;
-    size_t nstmts;
-
-    /* return handling */
-    Node *endlbl;
-    Node *ret;
-    int   isbigret;
-
-    /* pre/postinc handling */
-    Node **incqueue;
-    size_t nqueue;
-
-    /* location handling */
-    Node **blobs;
-    size_t nblobs;
-    size_t stksz;
-    size_t argsz;
-    Htab *globls;
-    Htab *locs;
-};
-
-static Node *simp(Simp *s, Node *n);
-static Node *rval(Simp *s, Node *n);
-static Node *lval(Simp *s, Node *n);
-static void declarelocal(Simp *s, Node *n);
-
-/* useful constants */
-static Node *one;
-static Node *zero;
-static Node *ptrsz;
-static Node *wordsz;
-static Type *tyword;
-static Type *tyvoid;
-
-static int max(int a, int b)
-{
-    if (a > b)
-        return a;
-    else
-        return b;
-}
-
-static Type *base(Type *t)
-{
-    assert(t->nsub == 1);
-    return t->sub[0];
-}
-
-static Node *add(Node *a, Node *b)
-{
-    Node *n;
-
-    n = mkexpr(a->line, Oadd, a, b, NULL);
-    n->expr.type = a->expr.type;
-    return n;
-}
-
-static Node *sub(Node *a, Node *b)
-{
-    Node *n;
-
-    n = mkexpr(a->line, Osub, a, b, NULL);
-    n->expr.type = a->expr.type;
-    return n;
-}
-
-static Node *mul(Node *a, Node *b)
-{
-    Node *n;
-
-    n = mkexpr(a->line, Omul, a, b, NULL);
-    n->expr.type = a->expr.type;
-    return n;
-}
-
-static Node *addr(Node *a, Type *bt)
-{
-    Node *n;
-
-    n = mkexpr(a->line, Oaddr, a, NULL);
-    if (!bt)
-        n->expr.type = mktyptr(a->line, a->expr.type);
-    else
-        n->expr.type = mktyptr(a->line, bt);
-    return n;
-}
-
-static Node *load(Node *a)
-{
-    Node *n;
-
-    n = mkexpr(a->line, Oload, a, NULL);
-    assert(a->expr.type->type == Typtr);
-    n->expr.type = base(a->expr.type);
-    return n;
-}
-
-static Node *store(Node *a, Node *b)
-{
-    Node *n;
-
-    assert(a != NULL && b != NULL);
-    n = mkexpr(a->line, Ostor, a, b, NULL);
-    return n;
-}
-
-static Node *word(int line, uint v)
-{
-    Node *n;
-    n = mkintlit(line, v);
-    n->expr.type = tyword;
-    return n;
-}
-
-
-static size_t did(Node *n)
-{
-    if (n->type == Ndecl) {
-        return n->decl.did;
-    } else if (n->type == Nexpr) {
-        assert(exprop(n) == Ovar);
-        return n->expr.did;
-    }
-    dump(n, stderr);
-    die("Can't get did");
-    return 0;
-}
-
-static ulong dclhash(void *dcl)
-{
-    /* large-prime hash. meh. */
-    return did(dcl) * 366787;
-}
-
-static int dcleq(void *a, void *b)
-{
-    return did(a) == did(b);
-}
-
-static void append(Simp *s, Node *n)
-{
-    lappend(&s->stmts, &s->nstmts, n);
-}
-
-static int ispure(Node *n)
-{
-    return ispureop[exprop(n)];
-}
-
-static int isconstfn(Node *s)
-{
-    return s->decl.isconst && decltype(s)->type == Tyfunc;
-}
-
-static char *asmname(Node *n)
-{
-    char *s;
-    int len;
-
-    len = strlen(Fprefix);
-    if (n->name.ns)
-        len += strlen(n->name.ns) + 1; /* +1 for separator */
-    len += strlen(n->name.name);
-
-    s = xalloc(len + 1);
-    s[0] = '\0';
-    sprintf(s, "%s", Fprefix);
-    if (n->name.ns)
-        sprintf(s, "%s%s$", s, n->name.ns);
-    sprintf(s, "%s%s", s, n->name.name);
-    return s;
-}
-
-size_t tysize(Type *t)
-{
-    size_t sz;
-    size_t i;
-
-    sz = 0;
-    if (!t)
-        return 0;
-    switch (t->type) {
-        case Tyvoid:
-            die("void has no size");
-            return 1;
-        case Tybool: case Tychar: case Tyint8:
-        case Tybyte: case Tyuint8:
-            return 1;
-        case Tyint16: case Tyuint16:
-            return 2;
-        case Tyint: case Tyint32:
-        case Tyuint: case Tyuint32:
-        case Typtr: case Tyfunc:
-            return 4;
-
-        case Tyint64: case Tylong:
-        case Tyuint64: case Tyulong:
-            return 8;
-
-            /*end integer types*/
-        case Tyfloat32:
-            return 4;
-        case Tyfloat64:
-            return 8;
-        case Tyvalist:
-            return 4; /* ptr to first element of valist */
-
-        case Tyslice:
-            return 8; /* len; ptr */
-        case Tyalias:
-            return tysize(t->sub[0]);
-        case Tyarray:
-            assert(exprop(t->asize) == Olit);
-            return t->asize->expr.args[0]->lit.intval * tysize(t->sub[0]);
-        case Tytuple:
-        case Tystruct:
-            for (i = 0; i < t->nmemb; i++)
-                sz += size(t->sdecls[i]);
-            return sz;
-            break;
-        case Tyunion:
-            sz = Wordsz;
-            for (i = 0; i < t->nmemb; i++)
-                sz = max(sz, tysize(t->udecls[i]->etype) + Wordsz);
-            return sz;
-            break;
-        case Tybad: case Tyvar: case Typaram: case Tyname: case Ntypes:
-            die("Type %s does not have size; why did it get down to here?", tystr(t));
-            break;
-    }
-    return -1;
-}
-
-size_t size(Node *n)
-{
-    Type *t;
-
-    if (n->type == Nexpr)
-        t = n->expr.type;
-    else
-        t = n->decl.type;
-    return tysize(t);
-}
-
-static Node *gentemp(Simp *simp, Node *e, Type *ty, Node **dcl)
-{
-    char buf[128];
-    static int nexttmp;
-    Node *t, *r, *n;
-
-    snprintf(buf, 128, ".t%d", nexttmp++);
-    n = mkname(e->line, buf);
-    t = mkdecl(e->line, n, ty);
-    r = mkexpr(e->line, Ovar, n, NULL);
-    r->expr.type = t->decl.type;
-    r->expr.did = t->decl.did;
-    if (dcl)
-        *dcl = t;
-    return r;
-}
-
-static Node *temp(Simp *simp, Node *e)
-{
-    Node *t, *dcl;
-
-    assert(e->type == Nexpr);
-    t = gentemp(simp, e, e->expr.type, &dcl);
-    declarelocal(simp, dcl);
-    return t;
-}
-
-static void jmp(Simp *s, Node *lbl)
-{
-    append(s, mkexpr(lbl->line, Ojmp, lbl, NULL));
-}
-
-static void cjmp(Simp *s, Node *cond, Node *iftrue, Node *iffalse)
-{
-    Node *jmp;
-
-    jmp = mkexpr(cond->line, Ocjmp, cond, iftrue, iffalse, NULL);
-    append(s, jmp);
-}
-
-/* if foo; bar; else baz;;
- *      => cjmp (foo) :bar :baz */
-static void simpif(Simp *s, Node *n)
-{
-    Node *l1, *l2;
-    Node *c;
-
-    l1 = genlbl();
-    l2 = genlbl();
-    c = rval(s, n->ifstmt.cond);
-    cjmp(s, c, l1, l2);
-    simp(s, l1);
-    simp(s, n->ifstmt.iftrue);
-    simp(s, l2);
-    simp(s, n->ifstmt.iffalse);
-}
-
-/* init; while cond; body;; 
- *    => init
- *       jmp :cond
- *       :body
- *           ...body...
- *       :cond
- *           ...cond...
- *       cjmp (cond) :body :end
- *       :end
- */
-static void simploop(Simp *s, Node *n)
-{
-    Node *lbody;
-    Node *lend;
-    Node *lcond;
-    Node *t;
-
-    lbody = genlbl();
-    lcond = genlbl();
-    lend = genlbl();
-
-    simp(s, n->loopstmt.init);  /* init */
-    jmp(s, lcond);              /* goto test */
-    simp(s, lbody);             /* body lbl */
-    simp(s, n->loopstmt.body);  /* body */
-    simp(s, n->loopstmt.step);  /* step */
-    simp(s, lcond);             /* test lbl */
-    t = rval(s, n->loopstmt.cond);  /* test */
-    cjmp(s, t, lbody, lend);    /* repeat? */
-    simp(s, lend);              /* exit */
-}
-
-static void simpblk(Simp *s, Node *n)
-{
-    size_t i;
-
-    for (i = 0; i < n->block.nstmts; i++) {
-        simp(s, n->block.stmts[i]);
-    }
-}
-
-static Node *bloblit(Simp *s, Node *lit)
-{
-    Node *n, *t, *r;
-    char lbl[128];
-
-    n = mkname(lit->line, genlblstr(lbl, 128));
-    t = mkdecl(lit->line, n, lit->expr.type);
-    r = mkexpr(lit->line, Ovar, n, NULL);
-    r->expr.type = lit->expr.type;
-    r->expr.did = t->decl.did;
-    t->decl.init = lit;
-    htput(s->globls, t, strdup(lbl));
-    lappend(&s->blobs, &s->nblobs, t);
-    return r;
-}
-
-static size_t offsetof(Node *aggr, Node *memb)
-{
-    Type *ty;
-    Node **nl;
-    size_t i;
-    size_t off;
-
-    if (aggr->expr.type->type == Typtr)
-        aggr = aggr->expr.args[0];
-    ty = aggr->expr.type;
-    ty = tybase(ty);
-
-    assert(ty->type == Tystruct);
-    nl = ty->sdecls;
-    off = 0;
-    for (i = 0; i < ty->nmemb; i++) {
-        if (!strcmp(namestr(memb), declname(nl[i])))
-            return off;
-        off += size(nl[i]);
-    }
-    die("Could not find member %s in struct", namestr(memb));
-    return -1;
-}
-
-static Node *membaddr(Simp *s, Node *n)
-{
-    Node *t, *u, *r;
-    Node **args;
-
-    args = n->expr.args;
-    if (n->expr.type->type == Typtr) {
-        t = args[0];
-        t->expr.type = mktyptr(n->line, exprtype(n));
-    } else {
-        t = addr(args[0], exprtype(n));
-    }
-    u = word(n->line, offsetof(args[0], args[1]));
-    r = add(t, u);
-    r->expr.type = mktyptr(n->line, n->expr.type);
-    return r;
-}
-
-static Node *idxaddr(Simp *s, Node *n)
-{
-    Node *t, *u, *v; /* temps */
-    Node *r; /* result */
-    Node **args;
-    size_t sz;
-
-    assert(exprop(n) == Oidx);
-    args = n->expr.args;
-    if (exprtype(args[0])->type == Tyarray)
-        t = addr(args[0], exprtype(n));
-    else if (args[0]->expr.type->type == Tyslice)
-        t = load(addr(args[0], mktyptr(n->line, exprtype(n))));
-    else
-        die("Can't index type %s\n", tystr(n->expr.type));
-    assert(t->expr.type->type == Typtr);
-    u = rval(s, args[1]);
-    sz = size(n);
-    v = mul(u, word(n->line, sz));
-    r = add(t, v);
-    return r;
-}
-
-static Node *slicebase(Simp *s, Node *n, Node *off)
-{
-    Node *t, *u, *v;
-    int sz;
-
-    t = rval(s, n);
-    u = NULL;
-    switch (exprtype(n)->type) {
-        case Typtr:     u = n; break;
-        case Tyarray:   u = addr(t, base(exprtype(n))); break;
-        case Tyslice:   u = load(addr(t, mktyptr(n->line, base(exprtype(n))))); break;
-        default: die("Unslicable type %s", tystr(n->expr.type));
-    }
-    /* safe: all types we allow here have a sub[0] that we want to grab */
-    sz = tysize(n->expr.type->sub[0]);
-    v = mul(off, word(n->line, sz));
-    return add(u, v);
-}
-
-static Node *slicelen(Simp *s, Node *sl)
-{
-    /* *(&sl + 4) */
-    return load(add(addr(sl, tyword), ptrsz));
-}
-
-Node *lval(Simp *s, Node *n)
-{
-    Node *r;
-
-    switch (exprop(n)) {
-        case Ovar:      r = n;  break;
-        case Oidx:      r = idxaddr(s, n);      break;
-        case Omemb:     r = membaddr(s, n);     break;
-        default:
-            die("%s cannot be an lval", opstr(exprop(n)));
-            break;
-    }
-    return r;
-}
-
-static Node *simplazy(Simp *s, Node *n, Node *r)
-{
-    Node *a, *b;
-    Node *next;
-    Node *end;
-
-    next = genlbl();
-    end = genlbl();
-    a = rval(s, n->expr.args[0]);
-    append(s, store(r, a));
-    if (exprop(n) == Oland)
-        cjmp(s, a, next, end);
-    else if (exprop(n) == Olor)
-        cjmp(s, a, end, next);
-    append(s, next);
-    b = rval(s, n->expr.args[1]);
-    append(s, store(r, b));
-    append(s, end);
-    return r;
-}
-
-static Node *lowerslice(Simp *s, Node *n)
-{
-    Node *t;
-    Node *base, *sz, *len;
-    Node *stbase, *stlen;
-
-    t = temp(s, n);
-    /* *(&slice) = (void*)base + off*sz */
-    base = slicebase(s, n->expr.args[0], n->expr.args[1]);
-    len = sub(n->expr.args[2], n->expr.args[1]);
-    stbase = store(addr(t, tyword), base);
-    /* *(&slice + ptrsz) = len */
-    sz = add(addr(t, tyword), ptrsz);
-    stlen = store(sz, len);
-    append(s, stbase);
-    append(s, stlen);
-    return t;
-}
-
-static Node *lowercast(Simp *s, Node *n)
-{
-    Node **args;
-    Node *r;
-
-    r = NULL;
-    args = n->expr.args;
-    switch (exprtype(n)->type) {
-        case Typtr:
-            switch (exprtype(args[0])->type) {
-                case Tyslice:
-                    r = slicebase(s, args[0], zero);
-                    break;
-                case Tyint:
-                    args[0]->expr.type = n->expr.type;
-                    r = args[0];
-                    break;
-                default:
-                    fatal(n->line, "Bad cast from %s to %s",
-                          tystr(exprtype(args[0])), tystr(exprtype(n)));
-            }
-            break;
-        default:
-            fatal(n->line, "Bad cast from %s to %s",
-                  tystr(exprtype(args[0])), tystr(exprtype(n)));
-    }
-    return r;
-}
-
-static Node *visit(Simp *s, Node *n)
-{
-    size_t i;
-    Node *r;
-
-    for (i = 0; i < n->expr.nargs; i++)
-        n->expr.args[i] = rval(s, n->expr.args[i]);
-    if (ispure(n)) {
-        r = n;
-    } else {
-        if (exprtype(n)->type == Tyvoid) {
-            r = NULL;
-            append(s, n);
-        } else {
-            r = temp(s, n);
-            append(s, store(r, n));
-        }
-    }
-    return r;
-}
-
-static Node *lowerucon(Simp *s, Node *n)
-{
-    Node *tmp, *u, *tag, *elt, *sz;
-    Node *r;
-    Type *ty;
-    Ucon *uc;
-    size_t i;
-
-    /* find the ucon we're constructing here */
-    ty = tybase(n->expr.type);
-    for (i = 0; i < ty->nmemb; i++) {
-        if (!strcmp(namestr(n->expr.args[0]), namestr(ty->udecls[i]->name))) {
-            uc = ty->udecls[i];
-            break;
-        }
-    }
-
-    tmp = temp(s, n);
-    u = addr(tmp, exprtype(n));
-    tag = word(n->line, uc->id);
-    store(u, tag);
-    if (!uc->etype)
-        return tmp;
-
-    elt = rval(s, n->expr.args[1]);
-    u = add(u, wordsz);
-    if (tysize(uc->etype) > Wordsz) {
-        elt = addr(elt, uc->etype);
-        sz = word(n->line, tysize(uc->utype));
-        r = mkexpr(n->line, Oblit, u, elt, sz, NULL);
-    } else {
-        r = store(u, elt);
-    }
-    append(s, r);
-    return tmp;
-}
-
-static Node *rval(Simp *s, Node *n)
-{
-    Node *r; /* expression result */
-    Node *t, *u, *v; /* temporary nodes */
-    Node **args;
-    size_t i;
-    const Op fusedmap[] = {
-        [Oaddeq]        = Oadd,
-        [Osubeq]        = Osub,
-        [Omuleq]        = Omul,
-        [Odiveq]        = Odiv,
-        [Omodeq]        = Omod,
-        [Oboreq]        = Obor,
-        [Obandeq]       = Oband,
-        [Obxoreq]       = Obxor,
-        [Obsleq]        = Obsl,
-    };
-
-
-    r = NULL;
-    args = n->expr.args;
-    switch (exprop(n)) {
-        case Obad:
-        case Olor: case Oland:
-            r = temp(s, n);
-            simplazy(s, n, r);
-            break;
-        case Osize:
-            r = word(n->line, size(args[0]));
-            break;
-        case Oslice:
-            r = lowerslice(s, n);
-            break;
-        case Oidx:
-            t = idxaddr(s, n);
-            r = load(t);
-            break;
-        case Omemb:
-            if (exprtype(args[0])->type == Tyslice) {
-                assert(!strcmp(namestr(args[1]), "len"));
-                r = slicelen(s, args[0]);
-            } else if (exprtype(args[0])->type == Tyarray) {
-                assert(!strcmp(namestr(args[1]), "len"));
-                r = exprtype(args[0])->asize;
-            } else {
-                t = membaddr(s, n);
-                r = load(t);
-            }
-            break;
-        case Ocons:
-            r = lowerucon(s, n);
-            break;
-        case Ocast:
-            /* slice -> ptr cast */
-            r = lowercast(s, n);
-            break;
-
-        /* fused ops:
-         * foo ?= blah
-         *    =>
-         *     foo = foo ? blah*/
-        case Oaddeq: case Osubeq: case Omuleq: case Odiveq: case Omodeq:
-        case Oboreq: case Obandeq: case Obxoreq: case Obsleq: case Obsreq:
-            assert(fusedmap[exprop(n)] != Obad);
-            u = rval(s, args[0]);
-            v = rval(s, args[1]);
-            v = mkexpr(n->line, fusedmap[exprop(n)], u, v, NULL);
-            v->expr.type = u->expr.type;
-            r = store(u, v);
-            break;
-
-        /* ++expr(x)
-         *  => args[0] = args[0] + 1
-         *     expr(x) */
-        case Opreinc:
-            t = lval(s, args[0]);
-            r = store(t, add(t, one));
-            lappend(&s->incqueue, &s->nqueue, t);
-            break;
-        case Opredec:
-            t = lval(s, args[0]);
-            r = store(t, sub(t, one));
-            lappend(&s->incqueue, &s->nqueue, t);
-            break;
-
-        /* expr(x++)
-         *     =>
-         *      expr
-         *      x = x + 1
-         */
-        case Opostinc:
-            r = lval(s, args[0]);
-            t = store(r, add(one, r));
-            lappend(&s->incqueue, &s->nqueue, t);
-            break;
-        case Opostdec:
-            r = lval(s, args[0]);
-            t = store(r, sub(one, r));
-            lappend(&s->incqueue, &s->nqueue, t);
-            break;
-        case Olit:
-            switch (args[0]->lit.littype) {
-                case Lchr: case Lbool: case Lint:
-                    r = n;
-                    break;
-                case Lstr: case Larray: case Lflt:
-                    r = bloblit(s, n);
-                    break;
-                case Lfunc:
-                    die("Func lits not handled yet");
-                    break;
-            }
-            break;
-        case Ovar:
-            r = n;
-            break;
-        case Oret:
-            if (s->isbigret) {
-                t = rval(s, args[0]);
-                t = addr(t, exprtype(args[0]));
-                u = word(n->line, size(args[0]));
-                v = mkexpr(n->line, Oblit, s->ret, t, u, NULL);
-                append(s, v);
-            } else if (n->expr.nargs && n->expr.args[0]) {
-                t = s->ret;
-                t = store(t, rval(s, args[0]));
-                append(s, t);
-            }
-            jmp(s, s->endlbl);
-            break;
-        case Oasn:
-            t = lval(s, args[0]);
-            u = rval(s, args[1]);
-            if (size(n) > Wordsz) {
-                t = addr(t, exprtype(n));
-                u = addr(u, exprtype(n));
-                v = word(n->line, size(n));
-                r = mkexpr(n->line, Oblit, t, u, v, NULL);
-            } else {
-              r = store(t, u);
-            }
-            break;
-        case Ocall:
-            if (exprtype(n)->type != Tyvoid && size(n) > Wordsz) {
-                r = temp(s, n);
-                linsert(&n->expr.args, &n->expr.nargs, 1, addr(r, exprtype(n)));
-                for (i = 0; i < n->expr.nargs; i++)
-                    n->expr.args[i] = rval(s, n->expr.args[i]);
-                append(s, n);
-            } else {
-                r = visit(s, n);
-            }
-            break;
-        default:
-            r = visit(s, n);
-    }
-    return r;
-}
-
-static void declarelocal(Simp *s, Node *n)
-{
-    assert(n->type == Ndecl);
-    s->stksz += size(n);
-    if (debug)
-        printf("declare %s(%ld) at %zd\n", declname(n), n->decl.did, s->stksz);
-    htput(s->locs, n, (void*)s->stksz);
-}
-
-static void declarearg(Simp *s, Node *n)
-{
-    assert(n->type == Ndecl);
-    if (debug)
-        printf("declare %s(%ld) at %zd\n", declname(n), n->decl.did, -(s->argsz + 8));
-    htput(s->locs, n, (void*)-(s->argsz + 8));
-    s->argsz += size(n);
-}
-
-static Node *simp(Simp *s, Node *n)
-{
-    Node *r, *t, *u;
-    size_t i;
-
-    if (!n)
-        return NULL;
-    r = NULL;
-    switch (n->type) {
-        case Nblock:
-            simpblk(s, n);
-            break;
-        case Nifstmt:
-            simpif(s, n);
-            break;
-        case Nloopstmt:
-            simploop(s, n);
-            break;
-        case Nexpr:
-            r = rval(s, n);
-            if (r)
-                append(s, r);
-            /* drain the increment queue for this expr */
-            for (i = 0; i < s->nqueue; i++)
-                append(s, s->incqueue[i]);
-            lfree(&s->incqueue, &s->nqueue);
-            break;
-        case Nlit:
-            r = n;
-            break;
-        case Ndecl:
-            declarelocal(s, n);
-            if (n->decl.init) {
-                t = mkexpr(n->line, Ovar, n->decl.name, NULL);
-                u = mkexpr(n->line, Oasn, t, n->decl.init, NULL);
-                u->expr.type = n->decl.type;
-                t->expr.type = n->decl.type;
-                t->expr.did = n->decl.did;
-                simp(s, u);
-            }
-            break;
-        case Nlbl:
-            append(s, n);
-            break;
-        default:
-            die("Bad node passsed to simp()");
-            break;
-    }
-    return r;
-}
-
-static void reduce(Simp *s, Node *f)
-{
-    Node *dcl;
-    Type *ty;
-    size_t i;
-
-    assert(f->type == Nfunc);
-    s->nstmts = 0;
-    s->stmts = NULL;
-    s->endlbl = genlbl();
-    s->ret = NULL;
-
-    assert(f->type == Nfunc);
-
-    ty = f->func.type->sub[0];
-    if (ty->type != Tyvoid && tysize(ty) > Wordsz) {
-        s->isbigret = 1;
-        s->ret = gentemp(s, f, mktyptr(f->line, ty), &dcl);
-        declarearg(s, dcl);
-    } else if (ty->type != Tyvoid) {
-        s->isbigret = 0;
-        s->ret = gentemp(s, f, ty, &dcl);
-        declarelocal(s, dcl);
-    }
-
-    for (i = 0; i < f->func.nargs; i++) {
-      declarearg(s, f->func.args[i]);
-    }
-    simp(s, f->func.body);
-
-    append(s, s->endlbl);
-}
-
-static Func *lowerfn(Simp *s, char *name, Node *n)
-{
-    size_t i;
-    Func *fn;
-    Cfg *cfg;
-
-    if(debug)
-        printf("\n\nfunction %s\n", name);
-
-    if (!n->decl.init)
-        return NULL;
-    /* set up the simp context */
-    /* unwrap to the function body */
-    n = n->expr.args[0];
-    n = n->lit.fnval;
-    reduce(s, n);
-
-    if (debug)
-        for (i = 0; i < s->nstmts; i++)
-            dump(s->stmts[i], stdout);
-    for (i = 0; i < s->nstmts; i++) {
-        if (s->stmts[i]->type != Nexpr)
-            continue;
-        if (debugopt['f']) {
-            printf("FOLD FROM ----------\n");
-            dump(s->stmts[i], stdout);
-        }
-        s->stmts[i] = fold(s->stmts[i]);
-        if (debugopt['f']) {
-            printf("FOLD TO ------------\n");
-            dump(s->stmts[i], stdout);
-            printf("END ----------------\n");
-        }
-    }
-    cfg = mkcfg(s->stmts, s->nstmts);
-    if (debug)
-        dumpcfg(cfg, stdout);
-
-    fn = zalloc(sizeof(Func));
-    fn->name = strdup(name);
-    fn->isglobl = 1; /* FIXME: we should actually use the visibility of the sym... */
-    fn->stksz = s->stksz;
-    fn->locs = s->locs;
-    fn->ret = s->ret;
-    fn->cfg = cfg;
-    return fn;
-}
-
-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 lowerdcl(Node *dcl, Htab *globls, Func ***fn, size_t *nfn, Node ***blob, size_t *nblob)
-{
-    Simp s = {0,};
-    char *name;
-    Func *f;
-
-    name = asmname(dcl->decl.name);
-    s.locs = mkht(dclhash, dcleq);
-    s.globls = globls;
-    s.blobs = *blob;
-    s.nblobs = *nblob;
-
-    if (isconstfn(dcl)) {
-        if (!dcl->decl.isextern && !dcl->decl.isgeneric) {
-            f = lowerfn(&s, name, dcl->decl.init);
-            lappend(fn, nfn, f);
-        }
-    } else {
-        if (dcl->decl.init && exprop(dcl->decl.init) == Olit)
-            lappend(&s.blobs, &s.nblobs, dcl);
-        else
-            die("We don't lower globls with nonlit inits yet...");
-    }
-    *blob = s.blobs;
-    *nblob = s.nblobs;
-    free(name);
-}
-
-void gen(Node *file, char *out)
-{
-    Htab *globls;
-    Node **n, **blob;
-    Func **fn;
-    size_t nn, nfn, nblob;
-    size_t i;
-    FILE *fd;
-
-    /* declare useful constants */
-    tyword = mkty(-1, Tyint);
-    tyvoid = mkty(-1, Tyvoid);
-    one = word(-1, 1);
-    zero = word(-1, 0);
-    ptrsz = word(-1, Wordsz);
-    wordsz = word(-1, Wordsz);
-
-    fn = NULL;
-    nfn = 0;
-    blob = NULL;
-    nblob = 0;
-    n = file->file.stmts;
-    nn = file->file.nstmts;
-    globls = mkht(dclhash, dcleq);
-
-    /* We need to define all global variables before use */
-    fillglobls(file->file.globls, globls);
-
-    for (i = 0; i < nn; i++) {
-        switch (n[i]->type) {
-            case Nuse: /* nothing to do */ 
-                break;
-            case Ndecl:
-                lowerdcl(n[i], globls, &fn, &nfn, &blob, &nblob);
-                break;
-            default:
-                die("Bad node %s in toplevel", nodestr(n[i]->type));
-                break;
-        }
-    }
-
-    fd = fopen(out, "w");
-    if (!fd)
-        die("Couldn't open fd %s", out);
-
-    if (debug) {
-        for (i = 0; i < nblob; i++)
-            genblob(stdout, blob[i], globls);
-        for (i = 0; i < nfn; i++)
-            genasm(stdout, fn[i], globls);
-    }
-    fprintf(fd, ".data\n");
-    for (i = 0; i < nblob; i++)
-        genblob(fd, blob[i], globls);
-    fprintf(fd, ".text\n");
-    for (i = 0; i < nfn; i++)
-        genasm(fd, fn[i], globls);
-    fclose(fd);
-}
--- /dev/null
+++ b/8/simp.c
@@ -1,0 +1,1035 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.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 "opt.h"
+#include "asm.h"
+
+#include "platform.h" /* HACK. We need some platform specific code gen behavior. *sigh.* */
+
+/* takes a list of nodes, and reduces it (and it's subnodes) to a list
+ * following these constraints:
+ *      - All nodes are expression nodes
+ *      - Nodes with side effects are root nodes
+ *      - All nodes operate on machine-primitive types and tuples
+ */
+typedef struct Simp Simp;
+struct Simp {
+    int isglobl;
+
+    Node **stmts;
+    size_t nstmts;
+
+    /* return handling */
+    Node *endlbl;
+    Node *ret;
+    int   isbigret;
+
+    /* pre/postinc handling */
+    Node **incqueue;
+    size_t nqueue;
+
+    /* location handling */
+    Node **blobs;
+    size_t nblobs;
+    size_t stksz;
+    size_t argsz;
+    Htab *globls;
+    Htab *locs;
+};
+
+static Node *simp(Simp *s, Node *n);
+static Node *rval(Simp *s, Node *n);
+static Node *lval(Simp *s, Node *n);
+static void declarelocal(Simp *s, Node *n);
+
+/* useful constants */
+static Node *one;
+static Node *zero;
+static Node *ptrsz;
+static Node *wordsz;
+static Type *tyword;
+static Type *tyvoid;
+
+static int max(int a, int b)
+{
+    if (a > b)
+        return a;
+    else
+        return b;
+}
+
+static Type *base(Type *t)
+{
+    assert(t->nsub == 1);
+    return t->sub[0];
+}
+
+static Node *add(Node *a, Node *b)
+{
+    Node *n;
+
+    n = mkexpr(a->line, Oadd, a, b, NULL);
+    n->expr.type = a->expr.type;
+    return n;
+}
+
+static Node *sub(Node *a, Node *b)
+{
+    Node *n;
+
+    n = mkexpr(a->line, Osub, a, b, NULL);
+    n->expr.type = a->expr.type;
+    return n;
+}
+
+static Node *mul(Node *a, Node *b)
+{
+    Node *n;
+
+    n = mkexpr(a->line, Omul, a, b, NULL);
+    n->expr.type = a->expr.type;
+    return n;
+}
+
+static Node *addr(Node *a, Type *bt)
+{
+    Node *n;
+
+    n = mkexpr(a->line, Oaddr, a, NULL);
+    if (!bt)
+        n->expr.type = mktyptr(a->line, a->expr.type);
+    else
+        n->expr.type = mktyptr(a->line, bt);
+    return n;
+}
+
+static Node *load(Node *a)
+{
+    Node *n;
+
+    n = mkexpr(a->line, Oload, a, NULL);
+    assert(a->expr.type->type == Typtr);
+    n->expr.type = base(a->expr.type);
+    return n;
+}
+
+static Node *store(Node *a, Node *b)
+{
+    Node *n;
+
+    assert(a != NULL && b != NULL);
+    n = mkexpr(a->line, Ostor, a, b, NULL);
+    return n;
+}
+
+static Node *word(int line, uint v)
+{
+    Node *n;
+    n = mkintlit(line, v);
+    n->expr.type = tyword;
+    return n;
+}
+
+
+static size_t did(Node *n)
+{
+    if (n->type == Ndecl) {
+        return n->decl.did;
+    } else if (n->type == Nexpr) {
+        assert(exprop(n) == Ovar);
+        return n->expr.did;
+    }
+    dump(n, stderr);
+    die("Can't get did");
+    return 0;
+}
+
+static ulong dclhash(void *dcl)
+{
+    /* large-prime hash. meh. */
+    return did(dcl) * 366787;
+}
+
+static int dcleq(void *a, void *b)
+{
+    return did(a) == did(b);
+}
+
+static void append(Simp *s, Node *n)
+{
+    lappend(&s->stmts, &s->nstmts, n);
+}
+
+static int ispure(Node *n)
+{
+    return ispureop[exprop(n)];
+}
+
+static int isconstfn(Node *s)
+{
+    return s->decl.isconst && decltype(s)->type == Tyfunc;
+}
+
+static char *asmname(Node *n)
+{
+    char *s;
+    int len;
+
+    len = strlen(Fprefix);
+    if (n->name.ns)
+        len += strlen(n->name.ns) + 1; /* +1 for separator */
+    len += strlen(n->name.name);
+
+    s = xalloc(len + 1);
+    s[0] = '\0';
+    sprintf(s, "%s", Fprefix);
+    if (n->name.ns)
+        sprintf(s, "%s%s$", s, n->name.ns);
+    sprintf(s, "%s%s", s, n->name.name);
+    return s;
+}
+
+size_t tysize(Type *t)
+{
+    size_t sz;
+    size_t i;
+
+    sz = 0;
+    if (!t)
+        return 0;
+    switch (t->type) {
+        case Tyvoid:
+            die("void has no size");
+            return 1;
+        case Tybool: case Tychar: case Tyint8:
+        case Tybyte: case Tyuint8:
+            return 1;
+        case Tyint16: case Tyuint16:
+            return 2;
+        case Tyint: case Tyint32:
+        case Tyuint: case Tyuint32:
+        case Typtr: case Tyfunc:
+            return 4;
+
+        case Tyint64: case Tylong:
+        case Tyuint64: case Tyulong:
+            return 8;
+
+            /*end integer types*/
+        case Tyfloat32:
+            return 4;
+        case Tyfloat64:
+            return 8;
+        case Tyvalist:
+            return 4; /* ptr to first element of valist */
+
+        case Tyslice:
+            return 8; /* len; ptr */
+        case Tyalias:
+            return tysize(t->sub[0]);
+        case Tyarray:
+            assert(exprop(t->asize) == Olit);
+            return t->asize->expr.args[0]->lit.intval * tysize(t->sub[0]);
+        case Tytuple:
+        case Tystruct:
+            for (i = 0; i < t->nmemb; i++)
+                sz += size(t->sdecls[i]);
+            return sz;
+            break;
+        case Tyunion:
+            sz = Wordsz;
+            for (i = 0; i < t->nmemb; i++)
+                sz = max(sz, tysize(t->udecls[i]->etype) + Wordsz);
+            return sz;
+            break;
+        case Tybad: case Tyvar: case Typaram: case Tyname: case Ntypes:
+            die("Type %s does not have size; why did it get down to here?", tystr(t));
+            break;
+    }
+    return -1;
+}
+
+size_t size(Node *n)
+{
+    Type *t;
+
+    if (n->type == Nexpr)
+        t = n->expr.type;
+    else
+        t = n->decl.type;
+    return tysize(t);
+}
+
+static Node *gentemp(Simp *simp, Node *e, Type *ty, Node **dcl)
+{
+    char buf[128];
+    static int nexttmp;
+    Node *t, *r, *n;
+
+    snprintf(buf, 128, ".t%d", nexttmp++);
+    n = mkname(e->line, buf);
+    t = mkdecl(e->line, n, ty);
+    r = mkexpr(e->line, Ovar, n, NULL);
+    r->expr.type = t->decl.type;
+    r->expr.did = t->decl.did;
+    if (dcl)
+        *dcl = t;
+    return r;
+}
+
+static Node *temp(Simp *simp, Node *e)
+{
+    Node *t, *dcl;
+
+    assert(e->type == Nexpr);
+    t = gentemp(simp, e, e->expr.type, &dcl);
+    declarelocal(simp, dcl);
+    return t;
+}
+
+static void jmp(Simp *s, Node *lbl)
+{
+    append(s, mkexpr(lbl->line, Ojmp, lbl, NULL));
+}
+
+static void cjmp(Simp *s, Node *cond, Node *iftrue, Node *iffalse)
+{
+    Node *jmp;
+
+    jmp = mkexpr(cond->line, Ocjmp, cond, iftrue, iffalse, NULL);
+    append(s, jmp);
+}
+
+/* if foo; bar; else baz;;
+ *      => cjmp (foo) :bar :baz */
+static void simpif(Simp *s, Node *n)
+{
+    Node *l1, *l2;
+    Node *c;
+
+    l1 = genlbl();
+    l2 = genlbl();
+    c = rval(s, n->ifstmt.cond);
+    cjmp(s, c, l1, l2);
+    simp(s, l1);
+    simp(s, n->ifstmt.iftrue);
+    simp(s, l2);
+    simp(s, n->ifstmt.iffalse);
+}
+
+/* init; while cond; body;; 
+ *    => init
+ *       jmp :cond
+ *       :body
+ *           ...body...
+ *       :cond
+ *           ...cond...
+ *       cjmp (cond) :body :end
+ *       :end
+ */
+static void simploop(Simp *s, Node *n)
+{
+    Node *lbody;
+    Node *lend;
+    Node *lcond;
+    Node *t;
+
+    lbody = genlbl();
+    lcond = genlbl();
+    lend = genlbl();
+
+    simp(s, n->loopstmt.init);  /* init */
+    jmp(s, lcond);              /* goto test */
+    simp(s, lbody);             /* body lbl */
+    simp(s, n->loopstmt.body);  /* body */
+    simp(s, n->loopstmt.step);  /* step */
+    simp(s, lcond);             /* test lbl */
+    t = rval(s, n->loopstmt.cond);  /* test */
+    cjmp(s, t, lbody, lend);    /* repeat? */
+    simp(s, lend);              /* exit */
+}
+
+static void simpblk(Simp *s, Node *n)
+{
+    size_t i;
+
+    for (i = 0; i < n->block.nstmts; i++) {
+        simp(s, n->block.stmts[i]);
+    }
+}
+
+static Node *bloblit(Simp *s, Node *lit)
+{
+    Node *n, *t, *r;
+    char lbl[128];
+
+    n = mkname(lit->line, genlblstr(lbl, 128));
+    t = mkdecl(lit->line, n, lit->expr.type);
+    r = mkexpr(lit->line, Ovar, n, NULL);
+    r->expr.type = lit->expr.type;
+    r->expr.did = t->decl.did;
+    t->decl.init = lit;
+    htput(s->globls, t, strdup(lbl));
+    lappend(&s->blobs, &s->nblobs, t);
+    return r;
+}
+
+static size_t offsetof(Node *aggr, Node *memb)
+{
+    Type *ty;
+    Node **nl;
+    size_t i;
+    size_t off;
+
+    if (aggr->expr.type->type == Typtr)
+        aggr = aggr->expr.args[0];
+    ty = aggr->expr.type;
+    ty = tybase(ty);
+
+    assert(ty->type == Tystruct);
+    nl = ty->sdecls;
+    off = 0;
+    for (i = 0; i < ty->nmemb; i++) {
+        if (!strcmp(namestr(memb), declname(nl[i])))
+            return off;
+        off += size(nl[i]);
+    }
+    die("Could not find member %s in struct", namestr(memb));
+    return -1;
+}
+
+static Node *membaddr(Simp *s, Node *n)
+{
+    Node *t, *u, *r;
+    Node **args;
+
+    args = n->expr.args;
+    if (n->expr.type->type == Typtr) {
+        t = args[0];
+        t->expr.type = mktyptr(n->line, exprtype(n));
+    } else {
+        t = addr(args[0], exprtype(n));
+    }
+    u = word(n->line, offsetof(args[0], args[1]));
+    r = add(t, u);
+    r->expr.type = mktyptr(n->line, n->expr.type);
+    return r;
+}
+
+static Node *idxaddr(Simp *s, Node *n)
+{
+    Node *t, *u, *v; /* temps */
+    Node *r; /* result */
+    Node **args;
+    size_t sz;
+
+    assert(exprop(n) == Oidx);
+    args = n->expr.args;
+    if (exprtype(args[0])->type == Tyarray)
+        t = addr(args[0], exprtype(n));
+    else if (args[0]->expr.type->type == Tyslice)
+        t = load(addr(args[0], mktyptr(n->line, exprtype(n))));
+    else
+        die("Can't index type %s\n", tystr(n->expr.type));
+    assert(t->expr.type->type == Typtr);
+    u = rval(s, args[1]);
+    sz = size(n);
+    v = mul(u, word(n->line, sz));
+    r = add(t, v);
+    return r;
+}
+
+static Node *slicebase(Simp *s, Node *n, Node *off)
+{
+    Node *t, *u, *v;
+    int sz;
+
+    t = rval(s, n);
+    u = NULL;
+    switch (exprtype(n)->type) {
+        case Typtr:     u = n; break;
+        case Tyarray:   u = addr(t, base(exprtype(n))); break;
+        case Tyslice:   u = load(addr(t, mktyptr(n->line, base(exprtype(n))))); break;
+        default: die("Unslicable type %s", tystr(n->expr.type));
+    }
+    /* safe: all types we allow here have a sub[0] that we want to grab */
+    sz = tysize(n->expr.type->sub[0]);
+    v = mul(off, word(n->line, sz));
+    return add(u, v);
+}
+
+static Node *slicelen(Simp *s, Node *sl)
+{
+    /* *(&sl + 4) */
+    return load(add(addr(sl, tyword), ptrsz));
+}
+
+Node *lval(Simp *s, Node *n)
+{
+    Node *r;
+
+    switch (exprop(n)) {
+        case Ovar:      r = n;  break;
+        case Oidx:      r = idxaddr(s, n);      break;
+        case Omemb:     r = membaddr(s, n);     break;
+        default:
+            die("%s cannot be an lval", opstr(exprop(n)));
+            break;
+    }
+    return r;
+}
+
+static Node *simplazy(Simp *s, Node *n, Node *r)
+{
+    Node *a, *b;
+    Node *next;
+    Node *end;
+
+    next = genlbl();
+    end = genlbl();
+    a = rval(s, n->expr.args[0]);
+    append(s, store(r, a));
+    if (exprop(n) == Oland)
+        cjmp(s, a, next, end);
+    else if (exprop(n) == Olor)
+        cjmp(s, a, end, next);
+    append(s, next);
+    b = rval(s, n->expr.args[1]);
+    append(s, store(r, b));
+    append(s, end);
+    return r;
+}
+
+static Node *lowerslice(Simp *s, Node *n)
+{
+    Node *t;
+    Node *base, *sz, *len;
+    Node *stbase, *stlen;
+
+    t = temp(s, n);
+    /* *(&slice) = (void*)base + off*sz */
+    base = slicebase(s, n->expr.args[0], n->expr.args[1]);
+    len = sub(n->expr.args[2], n->expr.args[1]);
+    stbase = store(addr(t, tyword), base);
+    /* *(&slice + ptrsz) = len */
+    sz = add(addr(t, tyword), ptrsz);
+    stlen = store(sz, len);
+    append(s, stbase);
+    append(s, stlen);
+    return t;
+}
+
+static Node *lowercast(Simp *s, Node *n)
+{
+    Node **args;
+    Node *r;
+
+    r = NULL;
+    args = n->expr.args;
+    switch (exprtype(n)->type) {
+        case Typtr:
+            switch (exprtype(args[0])->type) {
+                case Tyslice:
+                    r = slicebase(s, args[0], zero);
+                    break;
+                case Tyint:
+                    args[0]->expr.type = n->expr.type;
+                    r = args[0];
+                    break;
+                default:
+                    fatal(n->line, "Bad cast from %s to %s",
+                          tystr(exprtype(args[0])), tystr(exprtype(n)));
+            }
+            break;
+        default:
+            fatal(n->line, "Bad cast from %s to %s",
+                  tystr(exprtype(args[0])), tystr(exprtype(n)));
+    }
+    return r;
+}
+
+static Node *visit(Simp *s, Node *n)
+{
+    size_t i;
+    Node *r;
+
+    for (i = 0; i < n->expr.nargs; i++)
+        n->expr.args[i] = rval(s, n->expr.args[i]);
+    if (ispure(n)) {
+        r = n;
+    } else {
+        if (exprtype(n)->type == Tyvoid) {
+            r = NULL;
+            append(s, n);
+        } else {
+            r = temp(s, n);
+            append(s, store(r, n));
+        }
+    }
+    return r;
+}
+
+static Node *lowerucon(Simp *s, Node *n)
+{
+    Node *tmp, *u, *tag, *elt, *sz;
+    Node *r;
+    Type *ty;
+    Ucon *uc;
+    size_t i;
+
+    /* find the ucon we're constructing here */
+    ty = tybase(n->expr.type);
+    for (i = 0; i < ty->nmemb; i++) {
+        if (!strcmp(namestr(n->expr.args[0]), namestr(ty->udecls[i]->name))) {
+            uc = ty->udecls[i];
+            break;
+        }
+    }
+
+    tmp = temp(s, n);
+    u = addr(tmp, exprtype(n));
+    tag = word(n->line, uc->id);
+    store(u, tag);
+    if (!uc->etype)
+        return tmp;
+
+    elt = rval(s, n->expr.args[1]);
+    u = add(u, wordsz);
+    if (tysize(uc->etype) > Wordsz) {
+        elt = addr(elt, uc->etype);
+        sz = word(n->line, tysize(uc->utype));
+        r = mkexpr(n->line, Oblit, u, elt, sz, NULL);
+    } else {
+        r = store(u, elt);
+    }
+    append(s, r);
+    return tmp;
+}
+
+static Node *rval(Simp *s, Node *n)
+{
+    Node *r; /* expression result */
+    Node *t, *u, *v; /* temporary nodes */
+    Node **args;
+    size_t i;
+    const Op fusedmap[] = {
+        [Oaddeq]        = Oadd,
+        [Osubeq]        = Osub,
+        [Omuleq]        = Omul,
+        [Odiveq]        = Odiv,
+        [Omodeq]        = Omod,
+        [Oboreq]        = Obor,
+        [Obandeq]       = Oband,
+        [Obxoreq]       = Obxor,
+        [Obsleq]        = Obsl,
+    };
+
+
+    r = NULL;
+    args = n->expr.args;
+    switch (exprop(n)) {
+        case Obad:
+        case Olor: case Oland:
+            r = temp(s, n);
+            simplazy(s, n, r);
+            break;
+        case Osize:
+            r = word(n->line, size(args[0]));
+            break;
+        case Oslice:
+            r = lowerslice(s, n);
+            break;
+        case Oidx:
+            t = idxaddr(s, n);
+            r = load(t);
+            break;
+        case Omemb:
+            if (exprtype(args[0])->type == Tyslice) {
+                assert(!strcmp(namestr(args[1]), "len"));
+                r = slicelen(s, args[0]);
+            } else if (exprtype(args[0])->type == Tyarray) {
+                assert(!strcmp(namestr(args[1]), "len"));
+                r = exprtype(args[0])->asize;
+            } else {
+                t = membaddr(s, n);
+                r = load(t);
+            }
+            break;
+        case Ocons:
+            r = lowerucon(s, n);
+            break;
+        case Ocast:
+            /* slice -> ptr cast */
+            r = lowercast(s, n);
+            break;
+
+        /* fused ops:
+         * foo ?= blah
+         *    =>
+         *     foo = foo ? blah*/
+        case Oaddeq: case Osubeq: case Omuleq: case Odiveq: case Omodeq:
+        case Oboreq: case Obandeq: case Obxoreq: case Obsleq: case Obsreq:
+            assert(fusedmap[exprop(n)] != Obad);
+            u = rval(s, args[0]);
+            v = rval(s, args[1]);
+            v = mkexpr(n->line, fusedmap[exprop(n)], u, v, NULL);
+            v->expr.type = u->expr.type;
+            r = store(u, v);
+            break;
+
+        /* ++expr(x)
+         *  => args[0] = args[0] + 1
+         *     expr(x) */
+        case Opreinc:
+            t = lval(s, args[0]);
+            r = store(t, add(t, one));
+            lappend(&s->incqueue, &s->nqueue, t);
+            break;
+        case Opredec:
+            t = lval(s, args[0]);
+            r = store(t, sub(t, one));
+            lappend(&s->incqueue, &s->nqueue, t);
+            break;
+
+        /* expr(x++)
+         *     =>
+         *      expr
+         *      x = x + 1
+         */
+        case Opostinc:
+            r = lval(s, args[0]);
+            t = store(r, add(one, r));
+            lappend(&s->incqueue, &s->nqueue, t);
+            break;
+        case Opostdec:
+            r = lval(s, args[0]);
+            t = store(r, sub(one, r));
+            lappend(&s->incqueue, &s->nqueue, t);
+            break;
+        case Olit:
+            switch (args[0]->lit.littype) {
+                case Lchr: case Lbool: case Lint:
+                    r = n;
+                    break;
+                case Lstr: case Larray: case Lflt:
+                    r = bloblit(s, n);
+                    break;
+                case Lfunc:
+                    die("Func lits not handled yet");
+                    break;
+            }
+            break;
+        case Ovar:
+            r = n;
+            break;
+        case Oret:
+            if (s->isbigret) {
+                t = rval(s, args[0]);
+                t = addr(t, exprtype(args[0]));
+                u = word(n->line, size(args[0]));
+                v = mkexpr(n->line, Oblit, s->ret, t, u, NULL);
+                append(s, v);
+            } else if (n->expr.nargs && n->expr.args[0]) {
+                t = s->ret;
+                t = store(t, rval(s, args[0]));
+                append(s, t);
+            }
+            jmp(s, s->endlbl);
+            break;
+        case Oasn:
+            t = lval(s, args[0]);
+            u = rval(s, args[1]);
+            if (size(n) > Wordsz) {
+                t = addr(t, exprtype(n));
+                u = addr(u, exprtype(n));
+                v = word(n->line, size(n));
+                r = mkexpr(n->line, Oblit, t, u, v, NULL);
+            } else {
+              r = store(t, u);
+            }
+            break;
+        case Ocall:
+            if (exprtype(n)->type != Tyvoid && size(n) > Wordsz) {
+                r = temp(s, n);
+                linsert(&n->expr.args, &n->expr.nargs, 1, addr(r, exprtype(n)));
+                for (i = 0; i < n->expr.nargs; i++)
+                    n->expr.args[i] = rval(s, n->expr.args[i]);
+                append(s, n);
+            } else {
+                r = visit(s, n);
+            }
+            break;
+        default:
+            r = visit(s, n);
+    }
+    return r;
+}
+
+static void declarelocal(Simp *s, Node *n)
+{
+    assert(n->type == Ndecl);
+    s->stksz += size(n);
+    if (debug)
+        printf("declare %s(%ld) at %zd\n", declname(n), n->decl.did, s->stksz);
+    htput(s->locs, n, (void*)s->stksz);
+}
+
+static void declarearg(Simp *s, Node *n)
+{
+    assert(n->type == Ndecl);
+    if (debug)
+        printf("declare %s(%ld) at %zd\n", declname(n), n->decl.did, -(s->argsz + 8));
+    htput(s->locs, n, (void*)-(s->argsz + 8));
+    s->argsz += size(n);
+}
+
+static Node *simp(Simp *s, Node *n)
+{
+    Node *r, *t, *u;
+    size_t i;
+
+    if (!n)
+        return NULL;
+    r = NULL;
+    switch (n->type) {
+        case Nblock:
+            simpblk(s, n);
+            break;
+        case Nifstmt:
+            simpif(s, n);
+            break;
+        case Nloopstmt:
+            simploop(s, n);
+            break;
+        case Nexpr:
+            r = rval(s, n);
+            if (r)
+                append(s, r);
+            /* drain the increment queue for this expr */
+            for (i = 0; i < s->nqueue; i++)
+                append(s, s->incqueue[i]);
+            lfree(&s->incqueue, &s->nqueue);
+            break;
+        case Nlit:
+            r = n;
+            break;
+        case Ndecl:
+            declarelocal(s, n);
+            if (n->decl.init) {
+                t = mkexpr(n->line, Ovar, n->decl.name, NULL);
+                u = mkexpr(n->line, Oasn, t, n->decl.init, NULL);
+                u->expr.type = n->decl.type;
+                t->expr.type = n->decl.type;
+                t->expr.did = n->decl.did;
+                simp(s, u);
+            }
+            break;
+        case Nlbl:
+            append(s, n);
+            break;
+        default:
+            die("Bad node passsed to simp()");
+            break;
+    }
+    return r;
+}
+
+static void reduce(Simp *s, Node *f)
+{
+    Node *dcl;
+    Type *ty;
+    size_t i;
+
+    assert(f->type == Nfunc);
+    s->nstmts = 0;
+    s->stmts = NULL;
+    s->endlbl = genlbl();
+    s->ret = NULL;
+
+    assert(f->type == Nfunc);
+
+    ty = f->func.type->sub[0];
+    if (ty->type != Tyvoid && tysize(ty) > Wordsz) {
+        s->isbigret = 1;
+        s->ret = gentemp(s, f, mktyptr(f->line, ty), &dcl);
+        declarearg(s, dcl);
+    } else if (ty->type != Tyvoid) {
+        s->isbigret = 0;
+        s->ret = gentemp(s, f, ty, &dcl);
+        declarelocal(s, dcl);
+    }
+
+    for (i = 0; i < f->func.nargs; i++) {
+      declarearg(s, f->func.args[i]);
+    }
+    simp(s, f->func.body);
+
+    append(s, s->endlbl);
+}
+
+static Func *lowerfn(Simp *s, char *name, Node *n)
+{
+    size_t i;
+    Func *fn;
+    Cfg *cfg;
+
+    if(debug)
+        printf("\n\nfunction %s\n", name);
+
+    if (!n->decl.init)
+        return NULL;
+    /* set up the simp context */
+    /* unwrap to the function body */
+    n = n->expr.args[0];
+    n = n->lit.fnval;
+    reduce(s, n);
+
+    if (debug)
+        for (i = 0; i < s->nstmts; i++)
+            dump(s->stmts[i], stdout);
+    for (i = 0; i < s->nstmts; i++) {
+        if (s->stmts[i]->type != Nexpr)
+            continue;
+        if (debugopt['f']) {
+            printf("FOLD FROM ----------\n");
+            dump(s->stmts[i], stdout);
+        }
+        s->stmts[i] = fold(s->stmts[i]);
+        if (debugopt['f']) {
+            printf("FOLD TO ------------\n");
+            dump(s->stmts[i], stdout);
+            printf("END ----------------\n");
+        }
+    }
+    cfg = mkcfg(s->stmts, s->nstmts);
+    if (debug)
+        dumpcfg(cfg, stdout);
+
+    fn = zalloc(sizeof(Func));
+    fn->name = strdup(name);
+    fn->isglobl = 1; /* FIXME: we should actually use the visibility of the sym... */
+    fn->stksz = s->stksz;
+    fn->locs = s->locs;
+    fn->ret = s->ret;
+    fn->cfg = cfg;
+    return fn;
+}
+
+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 lowerdcl(Node *dcl, Htab *globls, Func ***fn, size_t *nfn, Node ***blob, size_t *nblob)
+{
+    Simp s = {0,};
+    char *name;
+    Func *f;
+
+    name = asmname(dcl->decl.name);
+    s.locs = mkht(dclhash, dcleq);
+    s.globls = globls;
+    s.blobs = *blob;
+    s.nblobs = *nblob;
+
+    if (isconstfn(dcl)) {
+        if (!dcl->decl.isextern && !dcl->decl.isgeneric) {
+            f = lowerfn(&s, name, dcl->decl.init);
+            lappend(fn, nfn, f);
+        }
+    } else {
+        if (dcl->decl.init && exprop(dcl->decl.init) == Olit)
+            lappend(&s.blobs, &s.nblobs, dcl);
+        else
+            die("We don't lower globls with nonlit inits yet...");
+    }
+    *blob = s.blobs;
+    *nblob = s.nblobs;
+    free(name);
+}
+
+void gen(Node *file, char *out)
+{
+    Htab *globls;
+    Node **n, **blob;
+    Func **fn;
+    size_t nn, nfn, nblob;
+    size_t i;
+    FILE *fd;
+
+    /* declare useful constants */
+    tyword = mkty(-1, Tyint);
+    tyvoid = mkty(-1, Tyvoid);
+    one = word(-1, 1);
+    zero = word(-1, 0);
+    ptrsz = word(-1, Wordsz);
+    wordsz = word(-1, Wordsz);
+
+    fn = NULL;
+    nfn = 0;
+    blob = NULL;
+    nblob = 0;
+    n = file->file.stmts;
+    nn = file->file.nstmts;
+    globls = mkht(dclhash, dcleq);
+
+    /* We need to define all global variables before use */
+    fillglobls(file->file.globls, globls);
+
+    for (i = 0; i < nn; i++) {
+        switch (n[i]->type) {
+            case Nuse: /* nothing to do */ 
+                break;
+            case Ndecl:
+                lowerdcl(n[i], globls, &fn, &nfn, &blob, &nblob);
+                break;
+            default:
+                die("Bad node %s in toplevel", nodestr(n[i]->type));
+                break;
+        }
+    }
+
+    fd = fopen(out, "w");
+    if (!fd)
+        die("Couldn't open fd %s", out);
+
+    if (debug) {
+        for (i = 0; i < nblob; i++)
+            genblob(stdout, blob[i], globls);
+        for (i = 0; i < nfn; i++)
+            genasm(stdout, fn[i], globls);
+    }
+    fprintf(fd, ".data\n");
+    for (i = 0; i < nblob; i++)
+        genblob(fd, blob[i], globls);
+    fprintf(fd, ".text\n");
+    for (i = 0; i < nfn; i++)
+        genasm(fd, fn[i], globls);
+    fclose(fd);
+}