ref: 91d7d2a303319f8a0fd2d2be1426bf4b03590bf0
parent: ccee477034a0a63df7a5864b375a243f8e4f246a
author: Ori Bernstein <ori@eigenstate.org>
date: Wed May 6 16:48:08 EDT 2015
A huge amount of work on checking. We now check for return types, and have a partly fleshed out use-before-def analysis.
--- a/mi/dfcheck.c
+++ b/mi/dfcheck.c
@@ -13,26 +13,166 @@
#include "parse.h"
#include "mi.h"
-/*
-static void nodeuse(Node *n, Bitset *bs)
+static void nodevars(Node *n, Bitset *bs)
{
+ size_t i;
+
+ if (!n || 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;
-static void nodedef(Node *n, Bitset *bs)
+ 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);
+ 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)
+ 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 bbuse(Bb *bb, Bitset *bs)
+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];
+ switch(exprop(n)) {
+ case Oset:
+ case Oasn:
+ checkdefined(n->expr.args[1], def);
+ break;
+ default:
+ checkdefined(n, def);
+ }
+ nodedef(n, def);
+ }
}
static void bbdef(Bb *bb, Bitset *bs)
{
+ size_t i;
+
+ if (!bb)
+ return;
+ for (i = 0; i < bb->nnl; i++)
+ nodedef(bb->nl[i], bs);
}
-*/
+static Bitset *indef(Cfg *cfg, Bb *bb, Bitset **outdef)
+{
+ size_t j;
+ Bitset *def;
+
+ j = 0;
+ if (!bsiter(bb->pred, &j))
+ return mkbs();
+ def = bsdup(outdef[j]);
+ for (; bsiter(bb->pred, &j); j++)
+ bsintersect(def, outdef[j]);
+ return def;
+}
+
static void checkreach(Cfg *cfg)
{
+ Bitset **outdef;
+ Bitset *def;
+ size_t i, j;
+ int changed;
+ Bb *bb;
+
+ outdef = xalloc(sizeof(Bitset*) * cfg->nbb);
+
+ def = mkbs();
+
+ for (i = 0; i < cfg->nbb; i++) {
+ outdef[i] = mkbs();
+ bbdef(cfg->bb[i], outdef[i]);
+ }
+
+ dumpcfg(cfg, stdout);
+ 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;
+ }
+
+ }
+ } 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);
+ }
}
static void checkpredret(Cfg *cfg, Bb *bb)
@@ -69,5 +209,6 @@
void check(Cfg *cfg)
{
checkret(cfg);
- checkreach(cfg);
+ if (0) /* Not quite ready yet. */
+ checkreach(cfg);
}
--- a/parse/ops.def
+++ b/parse/ops.def
@@ -56,7 +56,7 @@
O(Oarr, 1, OTmisc, NULL)
/* all below this point are backend-only */
-O(Odead, 0, OTmisc, "DEAD") /* unreachable code */
+O(Odead, 0, OTmisc, "DEAD") /* code */
O(Ocjmp, 1, OTmisc, "CJMP") /* conditional jump */
O(Ojtab, 1, OTmisc, "JTAB") /* jump table */
O(Oset, 1, OTbin, "=") /* store to var */