ref: 80ade912fa6ecf863d0f36ebc8fd3c999b45746e
dir: /mi/dfcheck.c/
#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 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; 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) 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); } } } 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 (!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; 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]); } 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; } } } 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) { Bb *pred; Op op; size_t i; for (i = 0; bsiter(bb->pred, &i); i++) { pred = cfg->bb[i]; if (pred->nnl == 0) { checkpredret(cfg, pred); } else { op = exprop(pred->nl[pred->nnl - 1]); if (op != Oret && op != Odead) { 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); if (0) checkreach(cfg); }