/* copy blocks and create definitions for the primed values as needed */ static void makenext(void) { SemBlock *b, *c; BitSet *copy; int i, j, ch; copy = bsnew(nblocks); for(i = 0; i < nblocks; i++) { b = blocks[i]; if(descendsum(b->phi, countnext) + descendsum(b->cont, countnext) > 0) bsadd(copy, i); } do { ch = 0; for(i = -1; i = bsiter(copy, i), i >= 0; ) { b = blocks[i]; for(j = 0; j < b->nto; j++) ch += bsadd(copy, b->to[j]->idx) == 0; for(j = 0; j < b->nfrom; j++) ch += bsadd(copy, b->from[j]->idx) == 0; } } while(ch != 0); dupl = emalloc(nblocks * sizeof(SemBlock *)); for(i = -1; i = bsiter(copy, i), i >= 0; ) dupl[i] = newblock(); for(i = -1; i = bsiter(copy, i), i >= 0; ) { b = blocks[i]; c = dupl[i]; c->nto = b->nto; c->to = emalloc(sizeof(SemBlock *) * c->nto); c->nfrom = b->nfrom; c->from = emalloc(sizeof(SemBlock *) * c->nfrom); for(j = 0; j < b->nto; j++) { c->to[j] = dupl[b->to[j]->idx]; assert(c->to[j] != nil); } for(j = 0; j < b->nfrom; j++) { c->from[j] = dupl[b->from[j]->idx]; assert(c->from[j] != nil); } c->phi = mkblock(descend(b->phi, nil, makenext1)); c->cont = mkblock(descend(b->cont, nil, makenext1)); c->jump = mkblock(descend(b->jump, nil, makenext1)); } for(i = 0; i < nblocks; i++) { b = blocks[i]; b->phi = mkblock(descend(b->phi, nil, deldefs)); b->cont = mkblock(descend(b->cont, nil, deldefs)); } bsfree(copy); }
void bsdump(Bitset *bs) { size_t i; for (i = 0; bsiter(bs, &i); i++) printf("%zd ", i); printf("\n"); }
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; bbin = mkbs(); for (j = 0; bsiter(cfg->bb[i]->pred, &j); j++) bsunion(bbin, out[j]); bbout = bsdup(bbin); bsdiff(bbout, kill[i]); bsunion(bbout, 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; }
static void addeq(BitSet *t, ASTNode **n, int p) { int i; Nodes *r; ASTNode *m; i = bsiter(t, -1); if(i < 0) return; if(*n != nil) r = nl(*n); else r = nil; for(; i >= 0; i = bsiter(t, i)){ m = node(ASTSYMB, stcur->vars[i]); r = nlcat(r, nl(node(ASTASS, OPNOP, p != 0 ? node(ASTPRIME, m) : m, m))); } *n = node(ASTBLOCK, r); }
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"); } } } }
/* Writes types to a file. Errors on * internal only types like Tyvar that * will not be meaningful in another file*/ static void typickle(FILE *fd, Type *ty) { size_t i; if (!ty) { die("trying to pickle null type\n"); return; } wrbyte(fd, ty->type); wrbyte(fd, ty->vis); /* tid is generated; don't write */ /* FIXME: since we only support hardcoded traits, we just write * out the set of them. we should write out the trait list as * well */ if (!ty->traits) { wrint(fd, 0); } else { wrint(fd, bscount(ty->traits)); for (i = 0; bsiter(ty->traits, &i); i++) { if (i < Ntraits) wrint(fd, i | Builtinmask); else wrint(fd, i); } } wrint(fd, ty->nsub); switch (ty->type) { case Tyunres: pickle(fd, ty->name); break; case Typaram: wrstr(fd, ty->pname); break; case Tystruct: wrint(fd, ty->nmemb); for (i = 0; i < ty->nmemb; i++) pickle(fd, ty->sdecls[i]); break; case Tyunion: wrint(fd, ty->nmemb); for (i = 0; i < ty->nmemb; i++) wrucon(fd, ty->udecls[i]); break; case Tyarray: wrtype(fd, ty->sub[0]); pickle(fd, ty->asize); break; case Tyslice: wrtype(fd, ty->sub[0]); break; case Tyvar: die("Attempting to pickle %s. This will not work.\n", tystr(ty)); break; case Tyname: pickle(fd, ty->name); wrbool(fd, ty->issynth); wrint(fd, ty->narg); for (i = 0; i < ty->narg; i++) wrtype(fd, ty->arg[i]); wrtype(fd, ty->sub[0]); break; case Tygeneric: pickle(fd, ty->name); wrbool(fd, ty->issynth); wrint(fd, ty->ngparam); for (i = 0; i < ty->ngparam; i++) wrtype(fd, ty->gparam[i]); wrtype(fd, ty->sub[0]); break; default: for (i = 0; i < ty->nsub; i++) wrtype(fd, ty->sub[i]); break; } }
/* liveness analysis * requires rpo computation */ void filllive(Fn *f) { Blk *b; Ins *i; int k, t, m[2], n, chg, nlv[2]; BSet u[1], v[1]; Mem *ma; bsinit(u, f->ntmp); bsinit(v, f->ntmp); for (b=f->start; b; b=b->link) { bsinit(b->in, f->ntmp); bsinit(b->out, f->ntmp); bsinit(b->gen, f->ntmp); } chg = 1; Again: for (n=f->nblk-1; n>=0; n--) { b = f->rpo[n]; bscopy(u, b->out); if (b->s1) { liveon(v, b, b->s1); bsunion(b->out, v); } if (b->s2) { liveon(v, b, b->s2); bsunion(b->out, v); } chg |= !bsequal(b->out, u); memset(nlv, 0, sizeof nlv); b->out->t[0] |= T.rglob; bscopy(b->in, b->out); for (t=0; bsiter(b->in, &t); t++) nlv[KBASE(f->tmp[t].cls)]++; if (rtype(b->jmp.arg) == RCall) { assert((int)bscount(b->in) == T.nrglob && nlv[0] == T.nrglob && nlv[1] == 0); b->in->t[0] |= T.retregs(b->jmp.arg, nlv); } else bset(b->jmp.arg, b, nlv, f->tmp); for (k=0; k<2; k++) b->nlive[k] = nlv[k]; for (i=&b->ins[b->nins]; i!=b->ins;) { if ((--i)->op == Ocall && rtype(i->arg[1]) == RCall) { b->in->t[0] &= ~T.retregs(i->arg[1], m); for (k=0; k<2; k++) { nlv[k] -= m[k]; /* caller-save registers are used * by the callee, in that sense, * right in the middle of the call, * they are live: */ nlv[k] += T.nrsave[k]; if (nlv[k] > b->nlive[k]) b->nlive[k] = nlv[k]; } b->in->t[0] |= T.argregs(i->arg[1], m); for (k=0; k<2; k++) { nlv[k] -= T.nrsave[k]; nlv[k] += m[k]; } } if (!req(i->to, R)) { assert(rtype(i->to) == RTmp); t = i->to.val; if (bshas(b->in, i->to.val)) nlv[KBASE(f->tmp[t].cls)]--; bsset(b->gen, t); bsclr(b->in, t); } for (k=0; k<2; k++) switch (rtype(i->arg[k])) { case RMem: ma = &f->mem[i->arg[k].val]; bset(ma->base, b, nlv, f->tmp); bset(ma->index, b, nlv, f->tmp); break; default: bset(i->arg[k], b, nlv, f->tmp); break; } for (k=0; k<2; k++) if (nlv[k] > b->nlive[k]) b->nlive[k] = nlv[k]; } } if (chg) { chg = 0; goto Again; } if (debug['L']) { fprintf(stderr, "\n> Liveness analysis:\n"); for (b=f->start; b; b=b->link) { fprintf(stderr, "\t%-10sin: ", b->name); dumpts(b->in, f->tmp, stderr); fprintf(stderr, "\t out: "); dumpts(b->out, f->tmp, stderr); fprintf(stderr, "\t gen: "); dumpts(b->gen, f->tmp, stderr); fprintf(stderr, "\t live: "); fprintf(stderr, "%d %d\n", b->nlive[0], b->nlive[1]); } } }