shithub: mc

Download patch

ref: 28318bd41da29f6e406c55247414cdcf3d071a30
parent: 87d2d8e139a034216b32cc752d4245837a4cc0f7
author: Ori Bernstein <[email protected]>
date: Thu Oct 30 09:27:35 EDT 2014

Unrename 'opt' -> 'mi'

--- a/6/Makefile
+++ b/6/Makefile
@@ -8,7 +8,7 @@
 	simp.o \
 	typeinfo.o \
 
-DEPS=../parse/libparse.a ../opt/libmi.a
+DEPS=../parse/libparse.a ../mi/libmi.a
 
 include ../config.mk
 include ../mk/c.mk
--- a/6/gen.c
+++ b/6/gen.c
@@ -10,7 +10,7 @@
 #include <unistd.h>
 
 #include "parse.h"
-#include "opt.h"
+#include "mi.h"
 #include "asm.h"
 #include "../config.h"
 
--- a/6/isel.c
+++ b/6/isel.c
@@ -12,7 +12,7 @@
 #include <unistd.h>
 
 #include "parse.h"
-#include "opt.h"
+#include "mi.h"
 #include "asm.h"
 #include "../config.h"
 
--- a/6/locs.c
+++ b/6/locs.c
@@ -11,7 +11,7 @@
 #include <unistd.h>
 
 #include "parse.h"
-#include "opt.h"
+#include "mi.h"
 #include "asm.h"
 #include "../config.h"
 
--- a/6/main.c
+++ b/6/main.c
@@ -13,7 +13,7 @@
 #include <sys/wait.h>
 
 #include "parse.h"
-#include "opt.h"
+#include "mi.h"
 #include "asm.h"
 
 #include "../config.h"
--- a/6/ra.c
+++ b/6/ra.c
@@ -7,7 +7,7 @@
 #include <string.h>
 
 #include "parse.h"
-#include "opt.h"
+#include "mi.h"
 #include "asm.h"
 
 #define Sizetbits (CHAR_BIT*sizeof(size_t)) /* used in graph reprs */
--- a/6/simp.c
+++ b/6/simp.c
@@ -10,7 +10,7 @@
 #include <unistd.h>
 
 #include "parse.h"
-#include "opt.h"
+#include "mi.h"
 #include "asm.h"
 #include "../config.h"
 
--- a/6/typeinfo.c
+++ b/6/typeinfo.c
@@ -10,7 +10,7 @@
 #include <unistd.h>
 
 #include "parse.h"
-#include "opt.h"
+#include "mi.h"
 #include "asm.h"
 #include "../config.h"
 
--- /dev/null
+++ b/mi/Makefile
@@ -1,0 +1,9 @@
+LIB=libmi.a
+OBJ=cfg.o \
+    fold.o \
+    match.o \
+    df.o \
+
+DEPS=../parse/libparse.a
+
+include ../mk/c.mk
--- /dev/null
+++ b/mi/cfg.c
@@ -1,0 +1,309 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdarg.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"
+
+
+static Bb *mkbb(Cfg *cfg)
+{
+    Bb *bb;
+
+    bb = zalloc(sizeof(Bb));
+    bb->id = cfg->nextbbid++;
+    bb->pred = mkbs();
+    bb->succ = mkbs();
+    lappend(&cfg->bb, &cfg->nbb, bb);
+    return bb;
+}
+
+static char *lblstr(Node *n)
+{
+    assert(exprop(n) == Olit);
+    assert(n->expr.args[0]->type == Nlit);
+    assert(n->expr.args[0]->lit.littype == Llbl);
+    return n->expr.args[0]->lit.lblval;
+}
+
+static void strlabel(Cfg *cfg, char *lbl, Bb *bb)
+{
+    htput(cfg->lblmap, lbl, bb);
+    lappend(&bb->lbls, &bb->nlbls, lbl);
+}
+
+static void label(Cfg *cfg, Node *lbl, Bb *bb)
+{
+    strlabel(cfg, lblstr(lbl), bb);
+}
+
+static int isnonretcall(Node *fn)
+{
+    Node *dcl;
+
+    if (exprop(fn) != Ovar)
+        return 0;
+    dcl = decls[fn->expr.did];
+    return dcl->decl.isnoret;
+}
+
+static int addnode(Cfg *cfg, Bb *bb, Node *n)
+{
+    switch (exprop(n)) {
+        case Ojmp:
+        case Ocjmp:
+        case Oret:
+            lappend(&bb->nl, &bb->nnl, n);
+            lappend(&cfg->fixjmp, &cfg->nfixjmp, n);
+            lappend(&cfg->fixblk, &cfg->nfixblk, bb);
+            return 1;
+            break;
+        case Ocall:
+            lappend(&bb->nl, &bb->nnl, n);
+            return isnonretcall(n->expr.args[0]);
+            break;
+        default:
+            lappend(&bb->nl, &bb->nnl, n);
+            break;
+    }
+    return 0;
+}
+
+static int islabel(Node *n)
+{
+    Node *l;
+    if (n->type != Nexpr)
+        return 0;
+    if (exprop(n) != Olit)
+        return 0;
+    l = n->expr.args[0];
+    if (l->type != Nlit)
+        return 0;
+    if (l->lit.littype != Llbl)
+        return 0;
+    return 1;
+}
+
+static Bb *addlabel(Cfg *cfg, Bb *bb, Node **nl, size_t i, Srcloc loc)
+{
+    /* if the current block assumes fall-through, insert an explicit jump */
+    if (i > 0 && nl[i - 1]->type == Nexpr) {
+        if (exprop(nl[i - 1]) != Ocjmp && exprop(nl[i - 1]) != Ojmp)
+            addnode(cfg, bb, mkexpr(loc, Ojmp, mklbl(loc, lblstr(nl[i])), NULL));
+    }
+    if (bb->nnl)
+        bb = mkbb(cfg);
+    label(cfg, nl[i], bb);
+    return bb;
+}
+
+void delete(Cfg *cfg, Bb *bb)
+{
+    size_t i, j;
+
+    if (bb == cfg->start || bb == cfg->end)
+        return;
+    for (i = 0; bsiter(bb->pred, &i); i++) {
+        bsunion(cfg->bb[i]->succ, bb->succ);
+        bsdel(cfg->bb[i]->succ, bb->id);
+    }
+    for (i = 0; bsiter(bb->succ, &i); i++) {
+        bsunion(cfg->bb[i]->pred, bb->pred);
+        bsdel(cfg->bb[i]->pred, bb->id);
+        for (j = 0; j < bb->nlbls; j++)
+            strlabel(cfg, bb->lbls[j], cfg->bb[i]);
+    }
+    cfg->bb[bb->id] = NULL;
+}
+
+void trimdead(Bb *bb)
+{
+    size_t i;
+
+    for (i = 0; i < bb->nnl; i++) {
+        switch (exprop(bb->nl[i])) {
+            /* if we're jumping, we can't keep going
+             * within this BB */
+            case Ojmp:
+            case Ocjmp:
+            case Oret:
+                bb->nnl = i + 1;
+                return;
+            case Ocall:
+                if (!isnonretcall(bb->nl[i]->expr.args[0]))
+                    break;
+                bb->nnl = i + 1;
+                return;
+            default:
+                /* nothing */
+                break;
+        }
+    }
+}
+
+void trim(Cfg *cfg)
+{
+    Bb *bb;
+    size_t i;
+
+    /* delete empty blocks and trivially unreachable code */
+    for (i = 0; i < cfg->nbb; i++) {
+
+        bb = cfg->bb[i];
+        if (bb->nnl == 0)
+            delete(cfg, bb);
+        else
+            trimdead(bb);
+    }
+}
+
+void delunreachable(Cfg *cfg)
+{
+    Bb *bb;
+    size_t i;
+    int deleted;
+
+    deleted = 1;
+    while (deleted) {
+        deleted = 0;
+        for (i = 0; i < cfg->nbb; i++) {
+            bb = cfg->bb[i];
+            if (bb == cfg->start || bb == cfg->end)
+                continue;
+            if (bb && bsisempty(bb->pred)) {
+                delete(cfg, bb);
+                deleted = 1;
+            }
+        }
+    }
+}
+
+Cfg *mkcfg(Node *fn, Node **nl, size_t nn)
+{
+    Cfg *cfg;
+    Bb *pre, *post;
+    Bb *bb, *targ;
+    Node *a, *b;
+    size_t i;
+
+    cfg = zalloc(sizeof(Cfg));
+    cfg->fn = fn;
+    cfg->lblmap = mkht(strhash, streq);
+    pre = mkbb(cfg);
+    bb = mkbb(cfg);
+    for (i = 0; i < nn; i++) {
+        switch (nl[i]->type) {
+            case Nexpr:
+                if (islabel(nl[i]))
+                    bb = addlabel(cfg, bb, nl, i, nl[i]->loc);
+                else if (addnode(cfg, bb, nl[i]))
+                    bb = mkbb(cfg);
+                break;
+                break;
+            case Ndecl:
+                break;
+            default:
+                die("Invalid node type %s in mkcfg", nodestr(nl[i]->type));
+        }
+    }
+    post = mkbb(cfg);
+    cfg->start = pre;
+    cfg->end = post;
+    bsput(pre->succ, cfg->bb[1]->id);
+    bsput(cfg->bb[1]->pred, pre->id);
+    bsput(cfg->bb[cfg->nbb - 2]->succ, post->id);
+    bsput(post->pred, cfg->bb[cfg->nbb - 2]->id);
+    trim(cfg);
+
+    for (i = 0; i < cfg->nfixjmp; i++) {
+        bb = cfg->fixblk[i];
+        switch (exprop(cfg->fixjmp[i])) {
+            case Ojmp:
+                a = cfg->fixjmp[i]->expr.args[0];
+                b = NULL;
+                break;
+            case Ocjmp:
+                a = cfg->fixjmp[i]->expr.args[1];
+                b = cfg->fixjmp[i]->expr.args[2];
+                break;
+            case Oret:
+                a = mklbl(cfg->fixjmp[i]->loc, cfg->end->lbls[0]);
+                b = NULL;
+                break;
+            default:
+                die("Bad jump fix thingy");
+                break;
+        }
+        if (a) {
+            targ = htget(cfg->lblmap, lblstr(a));
+            if (!targ)
+                die("No bb with label \"%s\"", lblstr(a));
+            bsput(bb->succ, targ->id);
+            bsput(targ->pred, bb->id);
+        }
+        if (b) {
+            targ = htget(cfg->lblmap, lblstr(b));
+            if (!targ)
+                die("No bb with label \"%s\"", lblstr(b));
+            bsput(bb->succ, targ->id);
+            bsput(targ->pred, bb->id);
+        }
+    }
+    delunreachable(cfg);
+    return cfg;
+}
+
+void dumpcfg(Cfg *cfg, FILE *fd)
+{
+    size_t i, j;
+    Bb *bb;
+    char *sep;
+
+    for (j = 0; j < cfg->nbb; j++) {
+        bb = cfg->bb[j];
+        if (!bb)
+            continue;
+        fprintf(fd, "\n");
+        fprintf(fd, "Bb: %d labels=(", bb->id);
+        sep = "";
+        for (i = 0; i < bb->nlbls; i++) {;
+            fprintf(fd, "%s%s", bb->lbls[i], sep);
+            sep = ",";
+        }
+        fprintf(fd, ")\n");
+
+        /* in edges */
+        fprintf(fd, "Pred: ");
+        sep = "";
+        for (i = 0; i < bsmax(bb->pred); i++) {
+            if (bshas(bb->pred, i)) {
+                fprintf(fd, "%s%zd", sep, i);
+                sep = ",";
+            }
+        }
+        fprintf(fd, "\n");
+
+        /* out edges */
+        fprintf(fd, "Succ: ");
+        sep = "";
+        for (i = 0; i < bsmax(bb->succ); i++) {
+             if (bshas(bb->succ, i)) {
+                fprintf(fd, "%s%zd", sep, i);
+                sep = ",";
+             }
+        }
+        fprintf(fd, "\n");
+
+        for (i = 0; i < bb->nnl; i++)
+            dump(bb->nl[i], fd);
+        fprintf(fd, "\n");
+    }
+}
--- /dev/null
+++ b/mi/df.c
@@ -1,0 +1,70 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdarg.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"
+
+/*
+static void nodeuse(Node *n, Bitset *bs)
+{
+}
+
+static void nodedef(Node *n, Bitset *bs)
+{
+}
+
+static void bbuse(Bb *bb, Bitset *bs)
+{
+}
+
+static void bbdef(Bb *bb, Bitset *bs)
+{
+}
+*/
+
+static void checkreach(Cfg *cfg)
+{
+}
+
+static void checkpredret(Cfg *cfg, Bb *bb)
+{
+    Bb *pred;
+    size_t i;
+
+    for (i = 0; bsiter(bb->pred, &i); i++) {
+        pred = cfg->bb[i];
+        if (pred->nnl == 0) {
+            checkpredret(cfg, pred);
+        } else if (exprop(pred->nl[pred->nnl - 1]) != Oret) {
+            dumpcfg(cfg, stdout);
+            fatal(pred->nl[pred->nnl-1], "Reaches end of function without return\n");
+        }
+    }
+}
+
+static void checkret(Cfg *cfg)
+{
+    Type *ft;
+
+    ft = tybase(decltype(cfg->fn));
+    assert(ft->type == Tyfunc);
+    if (ft->sub[0]->type == Tyvoid)
+        return;
+
+    checkpredret(cfg, cfg->end);
+}
+
+void check(Cfg *cfg)
+{
+    checkret(cfg);
+    checkreach(cfg);
+}
--- /dev/null
+++ b/mi/fold.c
@@ -1,0 +1,216 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdarg.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"
+
+static int islit(Node *n, vlong *v)
+{
+    Node *l;
+
+    if (exprop(n) != Olit)
+        return 0;
+    l = n->expr.args[0];
+    if (l->lit.littype != Lint)
+        return 0;
+    *v = l->lit.intval;
+    return 1;
+}
+
+static int isval(Node *n, vlong val)
+{
+    vlong v;
+
+    if (!islit(n, &v))
+        return 0;
+    return v == val;
+}
+
+static Node *val(Srcloc loc, vlong val, Type *t)
+{
+    Node *l, *n;
+
+    l = mkint(loc, val);
+    n = mkexpr(loc, Olit, l, NULL);
+    l->lit.type = t;
+    n->expr.type = t;
+    return n;
+}
+
+static int issmallconst(Node *dcl)
+{
+    Type *t;
+
+    if (!dcl->decl.isconst)
+        return 0;
+    if (!dcl->decl.init)
+        return 0;
+    t = tybase(exprtype(dcl->decl.init));
+    if (t->type <= Tyflt64)
+        return 1;
+    return 0;
+}
+
+static Node *foldcast(Node *n)
+{
+    Type *to, *from;
+    Node *sub;
+
+    sub = n->expr.args[0];
+    to = exprtype(n);
+    from = exprtype(sub);
+
+    switch (tybase(to)->type) {
+        case Tybool:
+        case Tyint8: case Tyint16: case Tyint32: case Tyint64:
+        case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
+        case Tyint: case Tyuint: case Tylong: case Tyulong:
+        case Tychar: case Tybyte:
+        case Typtr:
+            switch (tybase(from)->type) {
+                case Tybool:
+                case Tyint8: case Tyint16: case Tyint32: case Tyint64:
+                case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
+                case Tyint: case Tyuint: case Tylong: case Tyulong:
+                case Tychar: case Tybyte:
+                case Typtr:
+                    if (exprop(sub) == Olit || tybase(from)->type == tybase(to)->type) {
+                        sub->expr.type = to;
+                        return sub;
+                    } else {
+                        return n;
+                    }
+                default:
+                    return n;
+            }
+        default:
+            return n;
+    }
+    return n;
+}
+
+
+
+Node *fold(Node *n, int foldvar)
+{
+    Node **args, *r;
+    Type *t;
+    vlong a, b;
+    size_t i;
+
+    if (!n)
+        return NULL;
+    if (n->type != Nexpr)
+        return n;
+
+    r = NULL;
+    args = n->expr.args;
+    for (i = 0; i < n->expr.nargs; i++)
+        args[i] = fold(args[i], foldvar);
+    switch (exprop(n)) {
+        case Ovar:
+            if (foldvar && issmallconst(decls[n->expr.did]))
+                r = fold(decls[n->expr.did]->decl.init, foldvar);
+            break;
+        case Oadd:
+            /* x + 0 = 0 */
+            if (isval(args[0], 0))
+                r = args[1];
+            if (isval(args[1], 0))
+                r = args[0];
+            if (islit(args[0], &a) && islit(args[1], &b))
+                r = val(n->loc, a + b, exprtype(n));
+            break;
+        case Osub:
+            /* x - 0 = 0 */
+            if (isval(args[1], 0))
+                r = args[0];
+            if (islit(args[0], &a) && islit(args[1], &b))
+                r = val(n->loc, a - b, exprtype(n));
+            break;
+        case Omul:
+            /* 1 * x = x */
+            if (isval(args[0], 1))
+                r = args[1];
+            if (isval(args[1], 1))
+                r = args[0];
+            /* 0 * x = 0 */
+            if (isval(args[0], 0))
+                r = args[0];
+            if (isval(args[1], 0))
+                r = args[1];
+            if (islit(args[0], &a) && islit(args[1], &b))
+                r = val(n->loc, a * b, exprtype(n));
+            break;
+        case Odiv:
+            /* x/1 = x */
+            if (isval(args[1], 1))
+                r = args[0];
+            /* 0/x = 0 */
+            if (isval(args[1], 0))
+                r = args[1];
+            if (islit(args[0], &a) && islit(args[1], &b))
+                r = val(n->loc, a / b, exprtype(n));
+            break;
+        case Omod:
+            /* x%1 = x */
+            if (isval(args[1], 0))
+                r = args[0];
+            if (islit(args[0], &a) && islit(args[1], &b))
+                r = val(n->loc, a % b, exprtype(n));
+            break;
+        case Oneg:
+            if (islit(args[0], &a))
+                r = val(n->loc, -a, exprtype(n));
+            break;
+        case Obsl:
+            if (islit(args[0], &a) && islit(args[1], &b))
+                r = val(n->loc, a << b, exprtype(n));
+            break;
+        case Obsr:
+            if (islit(args[0], &a) && islit(args[1], &b))
+                r = val(n->loc, a >> b, exprtype(n));
+            break;
+        case Obor:
+            if (islit(args[0], &a) && islit(args[1], &b))
+                r = val(n->loc, a | b, exprtype(n));
+            break;
+        case Oband:
+            if (islit(args[0], &a) && islit(args[1], &b))
+                r = val(n->loc, a & b, exprtype(n));
+            break;
+        case Obxor:
+            if (islit(args[0], &a) && islit(args[1], &b))
+                r = val(n->loc, a ^ b, exprtype(n));
+            break;
+        case Omemb:
+            t = tybase(exprtype(args[0]));
+            /* we only fold lengths right now */
+            if (t->type == Tyarray && !strcmp(namestr(args[1]), "len"))
+                r = t->asize;
+            break;
+        case Ocast:
+            r = foldcast(n);
+            break;
+        default:
+            break;
+    }
+
+    if (r && n->expr.idx)
+      r->expr.idx = n->expr.idx;
+
+    if (r)
+        return r;
+    else
+        return n;
+}
+
--- /dev/null
+++ b/mi/match.c
@@ -1,0 +1,194 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdarg.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"
+
+typedef struct Dtree Dtree;
+struct Dtree {
+    /* If the values are equal, go to 'sub'. If 'val' is null, anything matches. */
+    Node **val;         /* values to compare against */
+    size_t nval;
+    Node **load;        /* values being loaded */
+    size_t nload;
+    Dtree **sub;        /* submatches for an equal comparison */
+    size_t nsub;
+    Dtree *any;         /* tree for a wildcard match. */
+
+    /* captured variables and action */
+    Node **cap;
+    size_t ncap;
+    Node *act;
+
+};
+
+static Dtree *addpat(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap);
+
+static Dtree *mkdtree()
+{
+    return zalloc(sizeof(Dtree));
+}
+
+static Dtree *addwild(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
+{
+    Node *dcl;
+
+    dcl = decls[pat->expr.did];
+    /* FIXME: Avoid duplicate constants */
+    if (dcl->decl.isconst)
+        return NULL;
+    if (t->any)
+        return t->any;
+    t->any = mkdtree();
+    lappend(cap, ncap, pat);
+    return t->any;
+}
+
+static Dtree *addunion(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
+{
+    Dtree *sub;
+    size_t i;
+
+    /* if we have the value already... */
+    sub = NULL;
+    for (i = 0; i < t->nval; i++) {
+        if (nameeq(t->val[i], pat->expr.args[0]))
+            return addpat(t->sub[i], pat->expr.args[1], NULL, cap, ncap);
+    }
+
+    sub = mkdtree();
+    lappend(&t->val, &t->nval, pat->expr.args[0]);
+    lappend(&t->sub, &t->nsub, sub);
+    if (pat->expr.nargs == 2)
+        sub = addpat(sub, pat->expr.args[1], NULL, cap, ncap);
+    return sub;
+}
+
+static Dtree *addlit(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
+{
+    Dtree *sub;
+    size_t i;
+
+    for (i = 0; i < t->nval; i++) {
+        if (liteq(t->val[i]->expr.args[0], pat->expr.args[0]))
+            return addpat(t->sub[i], pat->expr.args[1], NULL, cap, ncap);
+    }
+
+    sub = mkdtree();
+    lappend(&t->val, &t->nval, pat);
+    lappend(&t->sub, &t->nsub, sub);
+    return sub;
+}
+
+static Dtree *addtup(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
+{
+    size_t i;
+
+    for (i = 0; i < pat->expr.nargs; i++)
+        t = addpat(t, pat->expr.args[i], NULL, cap, ncap);
+    return t;
+}
+
+static Dtree *addarr(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
+{
+    size_t i;
+
+    for (i = 0; i < pat->expr.nargs; i++)
+        t = addpat(t, pat->expr.args[i], NULL, cap, ncap);
+    return t;
+}
+
+static Dtree *addstruct(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
+{
+    Node *elt;
+    size_t i, j;
+
+    for (i = 0; i < pat->expr.nargs; i++) {
+        elt = pat->expr.args[i];
+        for (j = 0; j < t->nval; j++) {
+            if (!strcmp(namestr(elt->expr.idx), namestr(t->val[j]->expr.idx)))
+                t = addpat(t, pat->expr.args[i], NULL, cap, ncap);
+            break;
+        }
+    }
+    return t;
+}
+
+static Dtree *addpat(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
+{
+    Dtree *ret;
+
+    if (pat == NULL)
+        return t;
+    switch (exprop(pat)) {
+        case Ovar:
+            ret = addwild(t, pat, val, cap, ncap);
+            break;
+        case Oucon:
+            ret = addunion(t, pat, val, cap, ncap);
+            break;
+        case Olit:
+            ret = addlit(t, pat, val, cap, ncap);
+            break;
+        case Otup:
+            ret = addtup(t, pat, val, cap, ncap);
+            break;
+        case Oarr:
+            ret = addarr(t, pat, val, cap, ncap);
+            break;
+        case Ostruct:
+            ret = addstruct(t, pat, val, cap, ncap);
+            break;
+        default:
+            ret = NULL;
+            fatal(pat, "unsupported pattern %s of type %s", opstr(exprop(pat)), tystr(exprtype(pat)));
+            break;
+    }
+
+    return ret;
+}
+
+static void checkcomprehensive(Dtree *dt)
+{
+}
+
+static Node *genmatch(Dtree *dt)
+{
+    return NULL;
+}
+
+Node *gensimpmatch(Node *m)
+{
+    Dtree *t, *leaf;
+    Node **pat, **cap;
+    size_t npat, ncap;
+    size_t i;
+
+    t = mkdtree();
+    pat = m->matchstmt.matches;
+    npat = m->matchstmt.nmatches;
+    cap = NULL;
+    ncap = 0;
+    for (i = 0; i < npat; i++) {
+        leaf = addpat(t, pat[i]->match.pat, NULL, &cap, &ncap);
+        /* TODO: NULL is returned by unsupported patterns. */
+        if (!leaf)
+            return NULL;
+        if (leaf->act)
+            fatal(pat[i], "pattern matched by earlier case");
+        leaf->act = pat[i]->match.block;
+        leaf->cap = cap;
+        leaf->ncap = ncap;
+    }
+    checkcomprehensive(t);
+    return genmatch(t);
+}
--- /dev/null
+++ b/mi/mi.h
@@ -1,0 +1,38 @@
+typedef struct Cfg Cfg;
+typedef struct Bb Bb;
+
+struct  Cfg {
+    Node *fn;
+    Bb **bb;
+    Bb *start;
+    Bb *end;
+    size_t nbb;
+
+    /* for building bb */
+    int nextbbid;
+    Htab *lblmap; /* label => Bb mapping */
+    Node **fixjmp;
+    size_t nfixjmp;
+    Bb **fixblk;
+    size_t nfixblk;
+};
+
+struct Bb {
+    int id;
+    char **lbls;
+    size_t nlbls;
+    Node **nl;
+    size_t nnl;
+    Bitset *pred;
+    Bitset *succ;
+};
+
+/* expression folding */
+Node *fold(Node *n, int foldvar);
+/* Takes a reduced block, and returns a flow graph. */
+Cfg *mkcfg(Node *fn, Node **nl, size_t nn);
+void dumpcfg(Cfg *c, FILE *fd);
+void check(Cfg *cfg);
+
+/* pattern matching */
+Node *gensimpmatch(Node *m);
--- /dev/null
+++ b/mi/mkfile
@@ -1,0 +1,14 @@
+</$objtype/mkfile
+CC=pcc
+LD=pcc
+CFLAGS=-c -D_POSIX_SOURCE -D_SUSV2_SOURCE -D_C99_SNPRINTF_EXTENSION -I../parse
+
+LIB=libopt.a
+OFILES=cfg.$O \
+    fold.$O \
+    df.$O
+
+HFILES=opt.h
+
+</sys/src/cmd/mklib
+
--- a/opt/Makefile
+++ /dev/null
@@ -1,9 +1,0 @@
-LIB=libmi.a
-OBJ=cfg.o \
-    fold.o \
-    match.o \
-    df.o \
-
-DEPS=../parse/libparse.a
-
-include ../mk/c.mk
--- a/opt/cfg.c
+++ /dev/null
@@ -1,309 +1,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <inttypes.h>
-#include <stdarg.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"
-
-
-static Bb *mkbb(Cfg *cfg)
-{
-    Bb *bb;
-
-    bb = zalloc(sizeof(Bb));
-    bb->id = cfg->nextbbid++;
-    bb->pred = mkbs();
-    bb->succ = mkbs();
-    lappend(&cfg->bb, &cfg->nbb, bb);
-    return bb;
-}
-
-static char *lblstr(Node *n)
-{
-    assert(exprop(n) == Olit);
-    assert(n->expr.args[0]->type == Nlit);
-    assert(n->expr.args[0]->lit.littype == Llbl);
-    return n->expr.args[0]->lit.lblval;
-}
-
-static void strlabel(Cfg *cfg, char *lbl, Bb *bb)
-{
-    htput(cfg->lblmap, lbl, bb);
-    lappend(&bb->lbls, &bb->nlbls, lbl);
-}
-
-static void label(Cfg *cfg, Node *lbl, Bb *bb)
-{
-    strlabel(cfg, lblstr(lbl), bb);
-}
-
-static int isnonretcall(Node *fn)
-{
-    Node *dcl;
-
-    if (exprop(fn) != Ovar)
-        return 0;
-    dcl = decls[fn->expr.did];
-    return dcl->decl.isnoret;
-}
-
-static int addnode(Cfg *cfg, Bb *bb, Node *n)
-{
-    switch (exprop(n)) {
-        case Ojmp:
-        case Ocjmp:
-        case Oret:
-            lappend(&bb->nl, &bb->nnl, n);
-            lappend(&cfg->fixjmp, &cfg->nfixjmp, n);
-            lappend(&cfg->fixblk, &cfg->nfixblk, bb);
-            return 1;
-            break;
-        case Ocall:
-            lappend(&bb->nl, &bb->nnl, n);
-            return isnonretcall(n->expr.args[0]);
-            break;
-        default:
-            lappend(&bb->nl, &bb->nnl, n);
-            break;
-    }
-    return 0;
-}
-
-static int islabel(Node *n)
-{
-    Node *l;
-    if (n->type != Nexpr)
-        return 0;
-    if (exprop(n) != Olit)
-        return 0;
-    l = n->expr.args[0];
-    if (l->type != Nlit)
-        return 0;
-    if (l->lit.littype != Llbl)
-        return 0;
-    return 1;
-}
-
-static Bb *addlabel(Cfg *cfg, Bb *bb, Node **nl, size_t i, Srcloc loc)
-{
-    /* if the current block assumes fall-through, insert an explicit jump */
-    if (i > 0 && nl[i - 1]->type == Nexpr) {
-        if (exprop(nl[i - 1]) != Ocjmp && exprop(nl[i - 1]) != Ojmp)
-            addnode(cfg, bb, mkexpr(loc, Ojmp, mklbl(loc, lblstr(nl[i])), NULL));
-    }
-    if (bb->nnl)
-        bb = mkbb(cfg);
-    label(cfg, nl[i], bb);
-    return bb;
-}
-
-void delete(Cfg *cfg, Bb *bb)
-{
-    size_t i, j;
-
-    if (bb == cfg->start || bb == cfg->end)
-        return;
-    for (i = 0; bsiter(bb->pred, &i); i++) {
-        bsunion(cfg->bb[i]->succ, bb->succ);
-        bsdel(cfg->bb[i]->succ, bb->id);
-    }
-    for (i = 0; bsiter(bb->succ, &i); i++) {
-        bsunion(cfg->bb[i]->pred, bb->pred);
-        bsdel(cfg->bb[i]->pred, bb->id);
-        for (j = 0; j < bb->nlbls; j++)
-            strlabel(cfg, bb->lbls[j], cfg->bb[i]);
-    }
-    cfg->bb[bb->id] = NULL;
-}
-
-void trimdead(Bb *bb)
-{
-    size_t i;
-
-    for (i = 0; i < bb->nnl; i++) {
-        switch (exprop(bb->nl[i])) {
-            /* if we're jumping, we can't keep going
-             * within this BB */
-            case Ojmp:
-            case Ocjmp:
-            case Oret:
-                bb->nnl = i + 1;
-                return;
-            case Ocall:
-                if (!isnonretcall(bb->nl[i]->expr.args[0]))
-                    break;
-                bb->nnl = i + 1;
-                return;
-            default:
-                /* nothing */
-                break;
-        }
-    }
-}
-
-void trim(Cfg *cfg)
-{
-    Bb *bb;
-    size_t i;
-
-    /* delete empty blocks and trivially unreachable code */
-    for (i = 0; i < cfg->nbb; i++) {
-
-        bb = cfg->bb[i];
-        if (bb->nnl == 0)
-            delete(cfg, bb);
-        else
-            trimdead(bb);
-    }
-}
-
-void delunreachable(Cfg *cfg)
-{
-    Bb *bb;
-    size_t i;
-    int deleted;
-
-    deleted = 1;
-    while (deleted) {
-        deleted = 0;
-        for (i = 0; i < cfg->nbb; i++) {
-            bb = cfg->bb[i];
-            if (bb == cfg->start || bb == cfg->end)
-                continue;
-            if (bb && bsisempty(bb->pred)) {
-                delete(cfg, bb);
-                deleted = 1;
-            }
-        }
-    }
-}
-
-Cfg *mkcfg(Node *fn, Node **nl, size_t nn)
-{
-    Cfg *cfg;
-    Bb *pre, *post;
-    Bb *bb, *targ;
-    Node *a, *b;
-    size_t i;
-
-    cfg = zalloc(sizeof(Cfg));
-    cfg->fn = fn;
-    cfg->lblmap = mkht(strhash, streq);
-    pre = mkbb(cfg);
-    bb = mkbb(cfg);
-    for (i = 0; i < nn; i++) {
-        switch (nl[i]->type) {
-            case Nexpr:
-                if (islabel(nl[i]))
-                    bb = addlabel(cfg, bb, nl, i, nl[i]->loc);
-                else if (addnode(cfg, bb, nl[i]))
-                    bb = mkbb(cfg);
-                break;
-                break;
-            case Ndecl:
-                break;
-            default:
-                die("Invalid node type %s in mkcfg", nodestr(nl[i]->type));
-        }
-    }
-    post = mkbb(cfg);
-    cfg->start = pre;
-    cfg->end = post;
-    bsput(pre->succ, cfg->bb[1]->id);
-    bsput(cfg->bb[1]->pred, pre->id);
-    bsput(cfg->bb[cfg->nbb - 2]->succ, post->id);
-    bsput(post->pred, cfg->bb[cfg->nbb - 2]->id);
-    trim(cfg);
-
-    for (i = 0; i < cfg->nfixjmp; i++) {
-        bb = cfg->fixblk[i];
-        switch (exprop(cfg->fixjmp[i])) {
-            case Ojmp:
-                a = cfg->fixjmp[i]->expr.args[0];
-                b = NULL;
-                break;
-            case Ocjmp:
-                a = cfg->fixjmp[i]->expr.args[1];
-                b = cfg->fixjmp[i]->expr.args[2];
-                break;
-            case Oret:
-                a = mklbl(cfg->fixjmp[i]->loc, cfg->end->lbls[0]);
-                b = NULL;
-                break;
-            default:
-                die("Bad jump fix thingy");
-                break;
-        }
-        if (a) {
-            targ = htget(cfg->lblmap, lblstr(a));
-            if (!targ)
-                die("No bb with label \"%s\"", lblstr(a));
-            bsput(bb->succ, targ->id);
-            bsput(targ->pred, bb->id);
-        }
-        if (b) {
-            targ = htget(cfg->lblmap, lblstr(b));
-            if (!targ)
-                die("No bb with label \"%s\"", lblstr(b));
-            bsput(bb->succ, targ->id);
-            bsput(targ->pred, bb->id);
-        }
-    }
-    delunreachable(cfg);
-    return cfg;
-}
-
-void dumpcfg(Cfg *cfg, FILE *fd)
-{
-    size_t i, j;
-    Bb *bb;
-    char *sep;
-
-    for (j = 0; j < cfg->nbb; j++) {
-        bb = cfg->bb[j];
-        if (!bb)
-            continue;
-        fprintf(fd, "\n");
-        fprintf(fd, "Bb: %d labels=(", bb->id);
-        sep = "";
-        for (i = 0; i < bb->nlbls; i++) {;
-            fprintf(fd, "%s%s", bb->lbls[i], sep);
-            sep = ",";
-        }
-        fprintf(fd, ")\n");
-
-        /* in edges */
-        fprintf(fd, "Pred: ");
-        sep = "";
-        for (i = 0; i < bsmax(bb->pred); i++) {
-            if (bshas(bb->pred, i)) {
-                fprintf(fd, "%s%zd", sep, i);
-                sep = ",";
-            }
-        }
-        fprintf(fd, "\n");
-
-        /* out edges */
-        fprintf(fd, "Succ: ");
-        sep = "";
-        for (i = 0; i < bsmax(bb->succ); i++) {
-             if (bshas(bb->succ, i)) {
-                fprintf(fd, "%s%zd", sep, i);
-                sep = ",";
-             }
-        }
-        fprintf(fd, "\n");
-
-        for (i = 0; i < bb->nnl; i++)
-            dump(bb->nl[i], fd);
-        fprintf(fd, "\n");
-    }
-}
--- a/opt/df.c
+++ /dev/null
@@ -1,70 +1,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <inttypes.h>
-#include <stdarg.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"
-
-/*
-static void nodeuse(Node *n, Bitset *bs)
-{
-}
-
-static void nodedef(Node *n, Bitset *bs)
-{
-}
-
-static void bbuse(Bb *bb, Bitset *bs)
-{
-}
-
-static void bbdef(Bb *bb, Bitset *bs)
-{
-}
-*/
-
-static void checkreach(Cfg *cfg)
-{
-}
-
-static void checkpredret(Cfg *cfg, Bb *bb)
-{
-    Bb *pred;
-    size_t i;
-
-    for (i = 0; bsiter(bb->pred, &i); i++) {
-        pred = cfg->bb[i];
-        if (pred->nnl == 0) {
-            checkpredret(cfg, pred);
-        } else if (exprop(pred->nl[pred->nnl - 1]) != Oret) {
-            dumpcfg(cfg, stdout);
-            fatal(pred->nl[pred->nnl-1], "Reaches end of function without return\n");
-        }
-    }
-}
-
-static void checkret(Cfg *cfg)
-{
-    Type *ft;
-
-    ft = tybase(decltype(cfg->fn));
-    assert(ft->type == Tyfunc);
-    if (ft->sub[0]->type == Tyvoid)
-        return;
-
-    checkpredret(cfg, cfg->end);
-}
-
-void check(Cfg *cfg)
-{
-    checkret(cfg);
-    checkreach(cfg);
-}
--- a/opt/fold.c
+++ /dev/null
@@ -1,216 +1,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <inttypes.h>
-#include <stdarg.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"
-
-static int islit(Node *n, vlong *v)
-{
-    Node *l;
-
-    if (exprop(n) != Olit)
-        return 0;
-    l = n->expr.args[0];
-    if (l->lit.littype != Lint)
-        return 0;
-    *v = l->lit.intval;
-    return 1;
-}
-
-static int isval(Node *n, vlong val)
-{
-    vlong v;
-
-    if (!islit(n, &v))
-        return 0;
-    return v == val;
-}
-
-static Node *val(Srcloc loc, vlong val, Type *t)
-{
-    Node *l, *n;
-
-    l = mkint(loc, val);
-    n = mkexpr(loc, Olit, l, NULL);
-    l->lit.type = t;
-    n->expr.type = t;
-    return n;
-}
-
-static int issmallconst(Node *dcl)
-{
-    Type *t;
-
-    if (!dcl->decl.isconst)
-        return 0;
-    if (!dcl->decl.init)
-        return 0;
-    t = tybase(exprtype(dcl->decl.init));
-    if (t->type <= Tyflt64)
-        return 1;
-    return 0;
-}
-
-static Node *foldcast(Node *n)
-{
-    Type *to, *from;
-    Node *sub;
-
-    sub = n->expr.args[0];
-    to = exprtype(n);
-    from = exprtype(sub);
-
-    switch (tybase(to)->type) {
-        case Tybool:
-        case Tyint8: case Tyint16: case Tyint32: case Tyint64:
-        case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
-        case Tyint: case Tyuint: case Tylong: case Tyulong:
-        case Tychar: case Tybyte:
-        case Typtr:
-            switch (tybase(from)->type) {
-                case Tybool:
-                case Tyint8: case Tyint16: case Tyint32: case Tyint64:
-                case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
-                case Tyint: case Tyuint: case Tylong: case Tyulong:
-                case Tychar: case Tybyte:
-                case Typtr:
-                    if (exprop(sub) == Olit || tybase(from)->type == tybase(to)->type) {
-                        sub->expr.type = to;
-                        return sub;
-                    } else {
-                        return n;
-                    }
-                default:
-                    return n;
-            }
-        default:
-            return n;
-    }
-    return n;
-}
-
-
-
-Node *fold(Node *n, int foldvar)
-{
-    Node **args, *r;
-    Type *t;
-    vlong a, b;
-    size_t i;
-
-    if (!n)
-        return NULL;
-    if (n->type != Nexpr)
-        return n;
-
-    r = NULL;
-    args = n->expr.args;
-    for (i = 0; i < n->expr.nargs; i++)
-        args[i] = fold(args[i], foldvar);
-    switch (exprop(n)) {
-        case Ovar:
-            if (foldvar && issmallconst(decls[n->expr.did]))
-                r = fold(decls[n->expr.did]->decl.init, foldvar);
-            break;
-        case Oadd:
-            /* x + 0 = 0 */
-            if (isval(args[0], 0))
-                r = args[1];
-            if (isval(args[1], 0))
-                r = args[0];
-            if (islit(args[0], &a) && islit(args[1], &b))
-                r = val(n->loc, a + b, exprtype(n));
-            break;
-        case Osub:
-            /* x - 0 = 0 */
-            if (isval(args[1], 0))
-                r = args[0];
-            if (islit(args[0], &a) && islit(args[1], &b))
-                r = val(n->loc, a - b, exprtype(n));
-            break;
-        case Omul:
-            /* 1 * x = x */
-            if (isval(args[0], 1))
-                r = args[1];
-            if (isval(args[1], 1))
-                r = args[0];
-            /* 0 * x = 0 */
-            if (isval(args[0], 0))
-                r = args[0];
-            if (isval(args[1], 0))
-                r = args[1];
-            if (islit(args[0], &a) && islit(args[1], &b))
-                r = val(n->loc, a * b, exprtype(n));
-            break;
-        case Odiv:
-            /* x/1 = x */
-            if (isval(args[1], 1))
-                r = args[0];
-            /* 0/x = 0 */
-            if (isval(args[1], 0))
-                r = args[1];
-            if (islit(args[0], &a) && islit(args[1], &b))
-                r = val(n->loc, a / b, exprtype(n));
-            break;
-        case Omod:
-            /* x%1 = x */
-            if (isval(args[1], 0))
-                r = args[0];
-            if (islit(args[0], &a) && islit(args[1], &b))
-                r = val(n->loc, a % b, exprtype(n));
-            break;
-        case Oneg:
-            if (islit(args[0], &a))
-                r = val(n->loc, -a, exprtype(n));
-            break;
-        case Obsl:
-            if (islit(args[0], &a) && islit(args[1], &b))
-                r = val(n->loc, a << b, exprtype(n));
-            break;
-        case Obsr:
-            if (islit(args[0], &a) && islit(args[1], &b))
-                r = val(n->loc, a >> b, exprtype(n));
-            break;
-        case Obor:
-            if (islit(args[0], &a) && islit(args[1], &b))
-                r = val(n->loc, a | b, exprtype(n));
-            break;
-        case Oband:
-            if (islit(args[0], &a) && islit(args[1], &b))
-                r = val(n->loc, a & b, exprtype(n));
-            break;
-        case Obxor:
-            if (islit(args[0], &a) && islit(args[1], &b))
-                r = val(n->loc, a ^ b, exprtype(n));
-            break;
-        case Omemb:
-            t = tybase(exprtype(args[0]));
-            /* we only fold lengths right now */
-            if (t->type == Tyarray && !strcmp(namestr(args[1]), "len"))
-                r = t->asize;
-            break;
-        case Ocast:
-            r = foldcast(n);
-            break;
-        default:
-            break;
-    }
-
-    if (r && n->expr.idx)
-      r->expr.idx = n->expr.idx;
-
-    if (r)
-        return r;
-    else
-        return n;
-}
-
--- a/opt/match.c
+++ /dev/null
@@ -1,194 +1,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <inttypes.h>
-#include <stdarg.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"
-
-typedef struct Dtree Dtree;
-struct Dtree {
-    /* If the values are equal, go to 'sub'. If 'val' is null, anything matches. */
-    Node **val;         /* values to compare against */
-    size_t nval;
-    Node **load;        /* values being loaded */
-    size_t nload;
-    Dtree **sub;        /* submatches for an equal comparison */
-    size_t nsub;
-    Dtree *any;         /* tree for a wildcard match. */
-
-    /* captured variables and action */
-    Node **cap;
-    size_t ncap;
-    Node *act;
-
-};
-
-static Dtree *addpat(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap);
-
-static Dtree *mkdtree()
-{
-    return zalloc(sizeof(Dtree));
-}
-
-static Dtree *addwild(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
-{
-    Node *dcl;
-
-    dcl = decls[pat->expr.did];
-    /* FIXME: Avoid duplicate constants */
-    if (dcl->decl.isconst)
-        return NULL;
-    if (t->any)
-        return t->any;
-    t->any = mkdtree();
-    lappend(cap, ncap, pat);
-    return t->any;
-}
-
-static Dtree *addunion(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
-{
-    Dtree *sub;
-    size_t i;
-
-    /* if we have the value already... */
-    sub = NULL;
-    for (i = 0; i < t->nval; i++) {
-        if (nameeq(t->val[i], pat->expr.args[0]))
-            return addpat(t->sub[i], pat->expr.args[1], NULL, cap, ncap);
-    }
-
-    sub = mkdtree();
-    lappend(&t->val, &t->nval, pat->expr.args[0]);
-    lappend(&t->sub, &t->nsub, sub);
-    if (pat->expr.nargs == 2)
-        sub = addpat(sub, pat->expr.args[1], NULL, cap, ncap);
-    return sub;
-}
-
-static Dtree *addlit(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
-{
-    Dtree *sub;
-    size_t i;
-
-    for (i = 0; i < t->nval; i++) {
-        if (liteq(t->val[i]->expr.args[0], pat->expr.args[0]))
-            return addpat(t->sub[i], pat->expr.args[1], NULL, cap, ncap);
-    }
-
-    sub = mkdtree();
-    lappend(&t->val, &t->nval, pat);
-    lappend(&t->sub, &t->nsub, sub);
-    return sub;
-}
-
-static Dtree *addtup(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
-{
-    size_t i;
-
-    for (i = 0; i < pat->expr.nargs; i++)
-        t = addpat(t, pat->expr.args[i], NULL, cap, ncap);
-    return t;
-}
-
-static Dtree *addarr(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
-{
-    size_t i;
-
-    for (i = 0; i < pat->expr.nargs; i++)
-        t = addpat(t, pat->expr.args[i], NULL, cap, ncap);
-    return t;
-}
-
-static Dtree *addstruct(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
-{
-    Node *elt;
-    size_t i, j;
-
-    for (i = 0; i < pat->expr.nargs; i++) {
-        elt = pat->expr.args[i];
-        for (j = 0; j < t->nval; j++) {
-            if (!strcmp(namestr(elt->expr.idx), namestr(t->val[j]->expr.idx)))
-                t = addpat(t, pat->expr.args[i], NULL, cap, ncap);
-            break;
-        }
-    }
-    return t;
-}
-
-static Dtree *addpat(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
-{
-    Dtree *ret;
-
-    if (pat == NULL)
-        return t;
-    switch (exprop(pat)) {
-        case Ovar:
-            ret = addwild(t, pat, val, cap, ncap);
-            break;
-        case Oucon:
-            ret = addunion(t, pat, val, cap, ncap);
-            break;
-        case Olit:
-            ret = addlit(t, pat, val, cap, ncap);
-            break;
-        case Otup:
-            ret = addtup(t, pat, val, cap, ncap);
-            break;
-        case Oarr:
-            ret = addarr(t, pat, val, cap, ncap);
-            break;
-        case Ostruct:
-            ret = addstruct(t, pat, val, cap, ncap);
-            break;
-        default:
-            ret = NULL;
-            fatal(pat, "unsupported pattern %s of type %s", opstr(exprop(pat)), tystr(exprtype(pat)));
-            break;
-    }
-
-    return ret;
-}
-
-static void checkcomprehensive(Dtree *dt)
-{
-}
-
-static Node *genmatch(Dtree *dt)
-{
-    return NULL;
-}
-
-Node *gensimpmatch(Node *m)
-{
-    Dtree *t, *leaf;
-    Node **pat, **cap;
-    size_t npat, ncap;
-    size_t i;
-
-    t = mkdtree();
-    pat = m->matchstmt.matches;
-    npat = m->matchstmt.nmatches;
-    cap = NULL;
-    ncap = 0;
-    for (i = 0; i < npat; i++) {
-        leaf = addpat(t, pat[i]->match.pat, NULL, &cap, &ncap);
-        /* TODO: NULL is returned by unsupported patterns. */
-        if (!leaf)
-            return NULL;
-        if (leaf->act)
-            fatal(pat[i], "pattern matched by earlier case");
-        leaf->act = pat[i]->match.block;
-        leaf->cap = cap;
-        leaf->ncap = ncap;
-    }
-    checkcomprehensive(t);
-    return genmatch(t);
-}
--- a/opt/mkfile
+++ /dev/null
@@ -1,14 +1,0 @@
-</$objtype/mkfile
-CC=pcc
-LD=pcc
-CFLAGS=-c -D_POSIX_SOURCE -D_SUSV2_SOURCE -D_C99_SNPRINTF_EXTENSION -I../parse
-
-LIB=libopt.a
-OFILES=cfg.$O \
-    fold.$O \
-    df.$O
-
-HFILES=opt.h
-
-</sys/src/cmd/mklib
-
--- a/opt/opt.h
+++ /dev/null
@@ -1,38 +1,0 @@
-typedef struct Cfg Cfg;
-typedef struct Bb Bb;
-
-struct  Cfg {
-    Node *fn;
-    Bb **bb;
-    Bb *start;
-    Bb *end;
-    size_t nbb;
-
-    /* for building bb */
-    int nextbbid;
-    Htab *lblmap; /* label => Bb mapping */
-    Node **fixjmp;
-    size_t nfixjmp;
-    Bb **fixblk;
-    size_t nfixblk;
-};
-
-struct Bb {
-    int id;
-    char **lbls;
-    size_t nlbls;
-    Node **nl;
-    size_t nnl;
-    Bitset *pred;
-    Bitset *succ;
-};
-
-/* expression folding */
-Node *fold(Node *n, int foldvar);
-/* Takes a reduced block, and returns a flow graph. */
-Cfg *mkcfg(Node *fn, Node **nl, size_t nn);
-void dumpcfg(Cfg *c, FILE *fd);
-void check(Cfg *cfg);
-
-/* pattern matching */
-Node *gensimpmatch(Node *m);