ref: d159e8c6b102a1c5d9a7625ecc8176f08290c259
dir: /mi/cfg.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 "util.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 void strlabel(Cfg *cfg, char *lbl, Bb *bb) { if (htget(cfg->lblmap, lbl) != 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; case Ocall: lappend(&bb->nl, &bb->nnl, n); return isnonretcall(n->expr.args[0]); case Odead: lappend(&bb->nl, &bb->nnl, n); return 1; 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 noexit(Cfg *cfg, Bb *bb) { size_t i; for (i = 0; bsiter(bb->succ, &i); i++) bsdel(cfg->bb[i]->pred, bb->id); bsclear(bb->succ); } void trimdead(Cfg *cfg, Bb *bb) { size_t i; if (!bb) return; 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 Odead: noexit(cfg, bb); bb->nnl = i + 1; return; case Ocall: if (isnonretcall(bb->nl[i]->expr.args[0])) { noexit(cfg, bb); bb->nnl = i + 1; return; } break; default: /* nothing */ break; } } } void trim(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; trimdead(cfg, bb); 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; static int nextret; char buf[32]; 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); bprintf(buf, sizeof buf, ".Lret%d", nextret++); label(cfg, mklbl(fn->loc, buf), post); 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); 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); } } if (debugopt['C']) dumpcfg(cfg, stdout); trim(cfg); return cfg; } void dumpbb(Bb *bb, FILE *fd) { size_t i; char *sep; 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"); } void dumpcfg(Cfg *cfg, FILE *fd) { size_t i; for (i = 0; i < cfg->nbb; i++) { if (!cfg->bb[i]) continue; fprintf(fd, "\n"); dumpbb(cfg->bb[i], fd); } }