shithub: mc

Download patch

ref: 3b2a10f280a9c927bd678199a90a96f8cddab89c
parent: 6cf64ac765264c305b91b3062ef8e3525e83add5
author: Ori Bernstein <[email protected]>
date: Thu May 7 21:06:17 EDT 2015

Get closer to a working use-before-def check.

--- a/mi/Makefile
+++ b/mi/Makefile
@@ -1,8 +1,10 @@
 LIB=libmi.a
 OBJ=cfg.o \
+    dfcheck.o \
     fold.o \
     match.o \
-    dfcheck.o \
+    reaching.o \
+
 
 DEPS=../parse/libparse.a
 
--- a/mi/dfcheck.c
+++ b/mi/dfcheck.c
@@ -13,195 +13,64 @@
 #include "parse.h"
 #include "mi.h"
 
-static void nodevars(Node *n, Bitset *bs)
+static void checkundef(Node *n, Reaching *r, Bitset *reach, Bitset *kill)
 {
-    size_t i;
+    size_t i, j, did;
+    Node *def;
 
-    if (!n || n->type != Nexpr)
+    if (n->type != Nexpr)
         return;
-    switch (exprop(n)) {
-        case Ovar:
-            bsput(bs, n->expr.did);
-            break;
-        default:
-            nodevars(n->expr.idx, bs);
-            for (i = 0; i < n->expr.nargs; i++)
-                nodevars(n->expr.args[i], bs);
-            break;
-    }
-}
-void nodedef(Node *n, Bitset *bs)
-{
-    Node *p;
-    size_t i;
-
-    switch(exprop(n)) {
-        case Oset:
-        case Oasn: case Oaddeq:
-        case Osubeq: case Omuleq:
-        case Odiveq: case Omodeq:
-        case Oboreq: case Obandeq:
-        case Obxoreq: case Obsleq:
-        case Obsreq:
-            nodevars(n->expr.args[0], bs);
-            nodedef(n->expr.args[1], bs);
-            break;
-            /* for the sake of less noise: assume that f(&var) inits the var. */
-        case Ocall:
-            for (i = 1; i < n->expr.nargs; i++) {
-                p = n->expr.args[i];
-                if (exprop(p) == Oaddr && exprop(p->expr.args[0]) == Ovar)
-                    nodevars(p, bs);
-            }
-            break;
-        default:
-            break;
-    }
-}
-
-static void checkdefined(Node *n, Bitset *def)
-{
-    size_t i;
-    Node *d;
-
-    if (!n || n->type != Nexpr)
-        return;
-    switch (exprop(n)) {
-        case Ovar:
-            d = decls[n->expr.did];
-            if (!bshas(def, n->expr.did) && !d->decl.isglobl)
+    if (exprop(n) == Ovar) {
+        did = n->expr.did;
+        for (j = 0; j < r->ndefs[did]; j++) {
+            if (bshas(kill, r->defs[did][j]))
+                continue;
+            if (bshas(reach, r->defs[did][j]))
+                def = nodes[r->defs[did][j]];
+            if (exprop(def) == Oundef)
                 fatal(n, "%s used before definition", namestr(n->expr.args[0]));
-            break;
-        default:
-            nodevars(n->expr.idx, def);
-            for (i = 0; i < n->expr.nargs; i++)
-                checkdefined(n->expr.args[i], def);
-            break;
-    }
-}
-
-static void checkuse(Bb *bb, Bitset *def)
-{
-    size_t i;
-    Node *n;
-
-    if (!bb)
-        return;
-    for (i = 0; i < bb->nnl; i++) {
-        n = bb->nl[i];
-        /* Tradeoff.
-         *
-         * We could check after, and get slightly more accurate checking,
-         * but then we error on things like:
-         *      init(&foo);
-         *
-         * We can check before, but then we don't error on things like:
-         *      x = f(x)
-         *
-         * Eventually we should check both ways. Right now, I want to get
-         * something working.
-         */
-        nodedef(n, def);
-        switch(exprop(n)) {
-            case Oset:
-            case Oasn:
-                checkdefined(n->expr.args[1], def);
-                break;
-            default:
-                checkdefined(n, def);
         }
+    } else {
+        for (i = 0; i < n->expr.nargs; i++)
+            checkundef(n->expr.args[i], r, reach, kill);
     }
 }
 
-static void bbdef(Bb *bb, Bitset *bs)
+void bsdump(Bitset *bs)
 {
     size_t i;
-
-    if (!bb)
-        return;
-    for (i = 0; i < bb->nnl; i++)
-        nodedef(bb->nl[i], bs);
+    for (i = 0; bsiter(bs, &i); i++)
+        printf("%zd ", i);
+    printf("\n");
 }
 
-static Bitset *indef(Cfg *cfg, Bb *bb, Bitset **outdef)
-{
-    size_t j;
-    Bitset *def;
-
-    j = 0;
-    if (!bb || !bsiter(bb->pred, &j))
-        return mkbs();
-    def = bsdup(outdef[j]);
-    for (; bsiter(bb->pred, &j); j++)
-        bsintersect(def, outdef[j]);
-    return def;
-}
-
-static void addargs(Cfg *cfg, Bitset *def)
-{
-    Node *n;
-    size_t i;
-
-    n = cfg->fn;
-    assert(n->type == Ndecl);
-    n = n->decl.init;
-    assert(n->type == Nexpr);
-    n = n->expr.args[0];
-    assert(n->type == Nlit);
-    n = n->lit.fnval;
-
-    for (i = 0; i < n->func.nargs; i++)
-        bsput(def,n->func.args[i]->decl.did); 
-}
-
 static void checkreach(Cfg *cfg)
 {
-    Bitset **outdef;
-    Bitset *def;
-    size_t i, j;
-    int changed;
+    Bitset *reach, *kill;
+    size_t i, j, k;
+    Reaching *r;
+    Node *n, *m;
     Bb *bb;
 
-    outdef = xalloc(sizeof(Bitset*) * cfg->nbb);
-
-    def = mkbs();
-
+    r = reaching(cfg);
     for (i = 0; i < cfg->nbb; i++) {
-        outdef[i] = mkbs();
-        bbdef(cfg->bb[i], outdef[i]);
-    }
-    addargs(cfg, outdef[cfg->start->id]);
-
-    for (i = 0; i < cfg->nbb; i++)
-        for (j= 0; bsiter(outdef[i], &j); j++)
-            printf("bb %zd defines %s\n", i, declname(decls[j]));
-
-    do {
-        changed = 0;
-        for (i = 0; i < cfg->nbb; i++) {
-            bb = cfg->bb[i];
-
-            def = indef(cfg, bb, outdef);
-            bsunion(def, outdef[i]);
-
-            if (!bseq(outdef[i], def)) {
-                changed = 1;
-                bsfree(outdef[i]);
-                outdef[i] = def;
+        bb = cfg->bb[i];
+        reach = bsdup(r->in[i]);
+        kill = mkbs();
+        for (j = 0; j < bb->nnl; j++) {
+            n = bb->nl[j];
+            if (exprop(n) == Oundef) {
+                bsput(reach, n->nid);
+            } else {
+                m = assignee(n);
+                if (m)
+                    for (k = 0; k < r->ndefs[m->expr.did]; k++)
+                        bsput(kill, r->defs[m->expr.did][k]);
+                checkundef(n, r, reach, kill);
             }
-
         }
-    } while (changed);
-
-
-
-    printf("---\n");
-    for (i = 0; i < cfg->nbb; i++) {
-        for (j= 0; bsiter(outdef[i], &j); j++)
-            printf("bb %zd defines %s\n", i, declname(decls[j]));
-        def = indef(cfg, bb, outdef);
-        checkuse(cfg->bb[i], def);
-        bsfree(def);
+        bsfree(reach);
+        bsfree(kill);
     }
 }
 
@@ -239,6 +108,6 @@
 void check(Cfg *cfg)
 {
     checkret(cfg);
-    if (0)
+    if(0)
         checkreach(cfg);
 }
--- a/mi/mi.h
+++ b/mi/mi.h
@@ -1,5 +1,6 @@
 typedef struct Cfg Cfg;
 typedef struct Bb Bb;
+typedef struct Reaching Reaching;
 
 struct  Cfg {
     Node *fn;
@@ -27,8 +28,20 @@
     Bitset *succ;
 };
 
+struct Reaching {
+    Bitset **in;
+    Bitset **out;
+    size_t **defs;
+    size_t *ndefs;
+};
+
 /* expression folding */
 Node *fold(Node *n, int foldvar);
+
+/* dataflow analysis */
+Reaching *reaching(Cfg *cfg);
+Node *assignee(Node *n);
+
 /* Takes a reduced block, and returns a flow graph. */
 Cfg *mkcfg(Node *fn, Node **nl, size_t nn);
 void dumpcfg(Cfg *c, FILE *fd);
--- /dev/null
+++ b/mi/reaching.c
@@ -1,0 +1,130 @@
+#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"
+
+Node *assignee(Node *n)
+{
+    switch (exprop(n)) {
+        case Oundef:
+        case Oset:
+        case Oasn: case Oaddeq:
+        case Osubeq: case Omuleq:
+        case Odiveq: case Omodeq:
+        case Oboreq: case Obandeq:
+        case Obxoreq: case Obsleq:
+        case Obsreq:
+            return n->expr.args[0];
+            break;
+        default:
+            break;
+    }
+    return NULL;
+}
+
+static void collectdefs(Cfg *cfg, size_t **defs, size_t *ndefs)
+{
+    size_t i, j, did;
+    Node *n;
+    Bb *bb;
+
+    for (i = 0; i < cfg->nbb; i++) {
+        bb = cfg->bb[i];
+        if (!bb)
+            continue;
+        for (j = 0; j < bb->nnl; j++) {
+            n = assignee(bb->nl[j]);
+            if (n && exprop(n) == Ovar) {
+                did = n->expr.did;
+                ndefs[did]++;
+                defs[did] = xrealloc(defs[did], ndefs[did] * sizeof(size_t));
+                defs[did][ndefs[did] - 1] = bb->nl[j]->nid;
+            }
+        }
+    }
+}
+
+static void genkill(Bb *bb, size_t **defs, size_t *ndefs, Bitset *gen, Bitset *kill)
+{
+    size_t i, j, did;
+    Node *n;
+
+    for (i = 0; i < bb->nnl; i++) {
+        n = assignee(bb->nl[i]);
+        if (!n)
+            continue;
+        did = n->expr.did;
+        bsput(gen, bb->nl[i]->nid);
+        for (j = 0; j < ndefs[did]; j++)
+            bsput(kill, defs[did][j]);
+    }
+}
+
+
+Reaching *reaching(Cfg *cfg)
+{
+    Bitset **in, **out;
+    Bitset **gen, **kill;
+    Bitset *bbin, *bbout;
+    Reaching *reaching;
+    size_t **defs;        /* mapping from did => [def,list] */
+    size_t *ndefs;      
+    size_t i, j;
+    int changed;
+
+    in = zalloc(cfg->nbb * sizeof(Bb*));
+    out = zalloc(cfg->nbb * sizeof(Bb*));
+    gen = zalloc(cfg->nbb * sizeof(Bb*));
+    kill = zalloc(cfg->nbb * sizeof(Bb*));
+    defs = zalloc(ndecls * sizeof(size_t*));
+    ndefs = zalloc(ndecls * sizeof(size_t));
+
+    collectdefs(cfg, defs, ndefs);
+    for (i = 0; i < cfg->nbb; i++) {
+        in[i] = mkbs();
+        out[i] = mkbs();
+        gen[i] = mkbs();
+        kill[i] = mkbs();
+        if (cfg->bb[i])
+            genkill(cfg->bb[i], defs, ndefs, gen[i], kill[i]);
+    }
+
+    do {
+        changed = 0;
+        for (i = 0; i < cfg->nbb; i++) {
+            if (!cfg->bb[i])
+                continue;
+            bbout = mkbs();
+            for (j = 0; bsiter(cfg->bb[i]->pred, &j); j++)
+                bsunion(bbout, in[j]);
+            bbin = bsdup(bbout);
+            bsdiff(bbin, kill[i]);
+            bsunion(bbin, gen[i]);
+
+            if (!bseq(out[i], bbout) || !bseq(in[i], bbin)) {
+                changed = 1;
+                bsfree(in[i]);
+                bsfree(out[i]);
+                in[i] = bbin;
+                out[i] = bbout;
+            }
+        }
+    } while (changed);
+
+    reaching = xalloc(sizeof(Reaching));
+    reaching->in = in;
+    reaching->out = out;
+    reaching->defs = defs;
+    reaching->ndefs = ndefs;
+    return reaching;
+}
--- a/parse/node.c
+++ b/parse/node.c
@@ -12,7 +12,8 @@
 
 #include "parse.h"
 
-size_t maxnid;
+Node **nodes;
+size_t nnodes;
 Node **decls;
 size_t ndecls;
 
@@ -49,9 +50,10 @@
     Node *n;
 
     n = zalloc(sizeof(Node));
-    n->nid = maxnid++;
+    n->nid = nnodes;
     n->type = nt;
     n->loc = loc;
+    lappend(&nodes, &nnodes, n);
     return n;
 }
 
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -375,10 +375,11 @@
 extern Trait **traittab;  /* int -> trait map */
 extern size_t ntraittab;
 extern Node **decls;    /* decl id -> decl map */
+extern size_t nnodes;
+extern Node **nodes;    /* node id -> node map */
 extern size_t ndecls;
 extern Node **exportimpls;
 extern size_t nexportimpls;
-extern size_t maxnid;      /* the maximum node id generated so far */
 
 /* property tables */
 extern int opispure[];