diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/8c/bound.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/8c/bound.c')
-rwxr-xr-x | sys/src/cmd/8c/bound.c | 1117 |
1 files changed, 1117 insertions, 0 deletions
diff --git a/sys/src/cmd/8c/bound.c b/sys/src/cmd/8c/bound.c new file mode 100755 index 000000000..d93c775ba --- /dev/null +++ b/sys/src/cmd/8c/bound.c @@ -0,0 +1,1117 @@ +#include "gc.h" +#include "bound.h" + +static BB* bbfree; +static BBset* bbsfree; +static int bballoc; +static int bbsalloc; +static BB bbz; +static BBset bbsz; +static BB* firstbb; +static BB* lastbb; +static BB* wounded; +static BB* bbaux; +static BBset* recalc; +static BBset* bbhash[BBHASH]; +static BB** ordered; +static int bcount; +static BBset** heap; +static int heapn; +static int bsize; +static char bbbuff[BBBSIZE]; +static int bchange; + +#define bdebug (debug['v']) +#define dbg 0 +#define bcheck 0 + +static long +Rn(Reg *r) +{ + if(r == R) + return -1; + return r->rpo; +} + +static BB* +bba(void) +{ + BB *b; + + bballoc++; + b = bbfree; + if(b == nil) { + b = alloc(sizeof(*b)); + } else + bbfree = b->link; + + *b = bbz; + return b; +} + +static void +bfree(BB *b) +{ + bballoc--; + b->link = bbfree; + bbfree = b; +} + +static BBset* +bbsa(void) +{ + BBset *b; + + bballoc++; + b = bbsfree; + if(b == nil) { + b = alloc(sizeof(*b)); + } else + bbsfree = b->link; + + *b = bbsz; + return b; +} + +static void +bsfree(BBset *b) +{ + bballoc--; + b->link = bbsfree; + bbsfree = b; +} + +static void +dumpheap(void) +{ + int i; + + for(i = 1; i <= heapn; i++) + print(" %d", heap[i]->damage); +} + +static void +checkheap(void) +{ + int N, N2, n, c; + + N = heapn; + N2 = N >> 1; + for(n = 1; n <= N2; n++) { + c = n << 1; + if((heap[c]->damage > heap[n]->damage) + || ((c < N) && (heap[c + 1]->damage > heap[n]->damage))) { + print("bad heap (%d:%d) %d [", n, heap[n]->damage, heapn); + dumpheap(); + print(" ]\n"); + abort(); + } + } +} + +static void +downheap(int n) +{ + int N, N2, d, c; + BBset *s, *t, *u; + + s = heap[n]; + d = s->damage; +//print("down %d %d", n, d); + N = heapn; + N2 = N >> 1; + while(n <= N2) { + c = n << 1; + t = heap[c]; + if(c < N) { + u = heap[c + 1]; + if(t->damage < u->damage) { + t = u; + c++; + } + } +//print(" [%d %d]", c, t->damage); + if(t->damage < d) + break; + heap[n] = t; + t->index = n; + n = c; + } + heap[n] = s; + s->index = n; +//print("\n"); +//checkheap(); +} + +static void +upheap(int n) +{ + int f, d; + BBset *s, *t; + + s = heap[n]; + d = s->damage; +//print("up %d %d", n, d); + while(n > 1) { + f = n >> 1; + t = heap[f]; +//print(" [%d %d]", f, t->damage); + if(t->damage >= d) + break; + heap[n] = t; + t->index = n; + n = f; + } + heap[n] = s; + s->index = n; +//print("\n"); +//checkheap(); +} + +static void +heapremove(BBset *s) +{ + int x; + BBset *t; + + x = s->index; + s->index = 0; + if(x == 0) + return; + if(x == heapn) { + heapn--; + return; + } + t = heap[heapn--]; + heap[x] = t; + t->index = x; + if(s->damage < t->damage) + upheap(x); + else + downheap(x); +} + +static void +heapadd(BBset *s) +{ + int n; + + n = heapn + 1; + heap[n] = s; + s->index = n; + heapn = n; + upheap(n); + +} + +static void +bbsrecalc(BBset *s) +{ + if(s->recalc) + return; + s->recalc = 1; + s->link = recalc; + recalc = s; + heapremove(s); +} + +static void +bbadd(BB *b, Hval h) +{ + int k; + BBset *s; + + k = h[0] & BBMASK; + for(s = bbhash[k]; s != nil; s = s->next) { + if(BBEQ(s->hash, h)) { + b->set = s; + b->link = s->ents; + s->ents = b; + bbsrecalc(s); + return; + } + } + s = bbsa(); + s->next = bbhash[k]; + bbhash[k] = s; + b->set = s; + b->link = nil; + s->ents = b; + BBCP(s->hash, h); + bbsrecalc(s); +} + +static int +hashbb(BB *b, Hval h) +{ + Reg *r; + Prog *p; + char *s; + int c, f, i, n; + + r = b->first; + s = bbbuff; + i = 0; + n = BBBSIZE; + for(;;) { + p = r->prog; + if(p->as != ANOP) { + if(p->to.type == D_BRANCH) + p->to.offset = r->s2->rpo; + c = snprint(s, n, "%P", p); + s += c; + n -= c; + i++; + } + if(r == b->last) + break; + r = r->link; + } + if(n == 0) + return Bbig; + b->len = i; + BBMKHASH(bbbuff, BBBSIZE - n, h); + f = b->flags; + if(i == 1 && r->prog->as == AJMP && b->first->p1 == R) + f = Bjo; + else if(b->first->p1 != R) + f |= Bpre; + if(bdebug) + print("A %x %s %ux %ux\n", f, bbbuff, h[0], h[1]); + return f; +} + +static void +enterbb(BB *b) +{ + Hval h; + + b->flags = hashbb(b, h); + if(b->flags != Bbig) + bbadd(b, h); +} + +static void +preproc(BB *b, int x) +{ + BB *n; + Reg *r; + + ordered[x] = b; + if(b->last->rpo - b->first->rpo > BBBIG) { + b->flags = Bbig; + return; + } + if(b->first->p2 == nil) { + b->flags = Bdel; + return; + } + switch(b->last->prog->as) { + case ARET: + case AJMP: + case AIRETL: + break; + + default: + b->flags = Bdel; + n = bba(); + n->first = b->first; + for(r = b->last->link; r != R; r = r->link) { + switch(r->prog->as) { + case ARET: + case AJMP: + case AIRETL: + n->last = r; + n->flags = Bpin; + enterbb(n); + if(n->flags & Bpin) { + n->aux = bbaux; + bbaux = n; + } + else + bfree(n); + return; + } + } + bfree(n); + return; + } + enterbb(b); +} + +static int +p2len(Reg *r) +{ + int c; + + c = 0; + for(r = r->p2; r != nil; r = r->p2link) + c++; + return c; +} + +static void +calcdamage(BBset *s) +{ + BB *f; + int d, t; + + s->recalc = 0; + f = s->ents; + if(f == nil) + return; + if(f->flags & Bjo) { + if(bdebug) + print("add %ld jo\n", f->first->rpo); + s->damage = COSTJO; + heapadd(s); + return; + } + if(f->link == nil) { + if(bdebug) + print("solo %x %x\n", s->hash[0], s->hash[1]); + return; + } + + d = 0; + t = 0; + while(f != nil) { + if((f->flags & (Bpre|Bpin)) == 0 && f->last->link != R) { + t = 1; + d += (f->last->rpo - f->first->rpo) >> 1; + } + d += p2len(f->first); + f = f->link; + } + + if(t == 0) { + if(bdebug) + print("all pre %ld\n", s->ents->first->rpo); + return; + } + + if(bdebug) + print("add %ld %d\n", s->ents->first->rpo, d); + if(d > COSTHI) + d = COSTHI; + s->damage = d; + heapadd(s); +} + +static Reg* +findjump(BB *b) +{ + Reg *r, *l; + + r = b->first; + l = b->last; + + for(;;) { + if(r->prog->as == AJMP) + break; + if(r == l) { + diag(Z, "findjump botch"); + break; + } + r = r->link; + } + return r; +} + +static BB* +findset(int r) +{ + BB *s, **p; + int n, n2; + + if(r < ordered[0]->first->rpo) + return nil; + n = bcount; + p = ordered; + while(n > 0) { + n2 = n >> 1; + s = p[n2]; + if(r < s->first->rpo) { + n = n2; + continue; + } + if(r > s->last->rpo) { + n2++; + p += n2; + n -= n2; + continue; + } + return s; + } + diag(Z, "findset botch"); + return nil; +} + +static void +wound(Reg *r) +{ + BB *b, *p, **n; + BBset *s; + + b = findset(r->rpo); + if(b == nil) + return; + s = b->set; + if(s == nil) + return; + for(n = &s->ents; (p = *n) != nil; n = &(*n)->link) { + if(p == b) { + *n = b->link; + b->link = wounded; + wounded = b; + bbsrecalc(s); + return; + } + } +} + +static void +printbl(Reg *l) +{ + if(l == nil) { + print("Z"); + return; + } + + print("%ld", l->rpo); + while((l = l->p2link) != nil) + print(" %ld", l->rpo); +} + +static void +appset(Reg *e, Reg *s) +{ + for(;;) { + if(s->p2link == R) { + s->p2link = e; + return; + } + s = s->p2link; + } +} + +static Reg* +delset(Reg *e, Reg *s) +{ + Reg *c, *l; + + c = s; + l = nil; + for(;;) { + if(e == c) { + if(l == nil) + return s->p2link; + l->p2link = c->p2link; + return s; + } + l = c; + c = c->p2link; + if(c == nil) + return s; + } +} + +static void +redest(Reg *s, Reg *d) +{ + while(s != R) { + s->s2 = d; + s = s->p2link; + } +} + +static void +changedest(Reg *s, Reg *d, int x) +{ + Reg *l; + + if(bdebug) { + print("change %ld [", s->rpo); + printbl(s->p2); + print("] -> %ld [", d->rpo); + printbl(d->p2); + print("]\n"); + } + + if(s->p2 == nil) { +// print("deadjmp\n"); + return; + } + + l = s->p2; + for(;;) { + if(bdebug) + print("s2 %ld = %ld\n", l->rpo, d->rpo); + l->s2 = d; + wound(l); + if(l->p2link == nil) + break; + l = l->p2link; + } + + if(x) { + l->p2link = delset(s, d->p2); + d->p2 = s->p2; + } + else { + l->p2link = d->p2; + d->p2 = s->p2; + s->p2 = nil; + } + + if(bdebug) { + print("result ["); + printbl(d->p2); + print("]\n"); + } + + bchange = 1; +} + +static void +bexcise(BB *b) +{ + Reg *r, *l; + + l = b->last; + r = b->first; + if(bdebug) + print("excise %ld to %ld\n", r->rpo, l->rpo); + for(;;) { + r->prog->as = ANOP; + r->prog->to.type = D_NONE; + r->p2 = R; + if(r->s2 != R) { + r->s2->p2 = delset(r, r->s2->p2); + r->s2 = R; + } + if(r == l) + break; + r = r->link; + } +} + +static int +backtrack(Reg *s, Reg *d) +{ + int i; + char l[BINST], r[BINST]; + +//print("backtrack %ld %ld\n", Rn(s), Rn(d)); + i = 0; + while(s != nil && d != nil) { + if(snprint(l, BINST, "%P", s->prog) == BINST) + break; + if(snprint(r, BINST, "%P", d->prog) == BINST) + break; +//print("%s\t%s\n", l, r); + if(strcmp(l, r) != 0) + break; + i++; + s = s->p2link; + d = d->p2link; + } + return i; +} + +static void +checktails(void) +{ + int c; + Reg *r; + + c = 0; + for(r = firstr; r->link != R; r = r->link) { + if(r->prog->as == AJMP && r->s2 != nil) + c += backtrack(r->p1, r->s2->p1); + } + + if(c > 0) + print("tails %s %d\n", firstr->prog->from.sym->name, c); +} + +static void +process(BBset *s) +{ + Reg *h; + BB *f, *o, *p, *t; + + if(bdebug) + print("process %d %x %x\n", s->damage, s->hash[0], s->hash[1]); + f = s->ents; + if(f->flags & Bjo) { + s->ents = nil; + h = findjump(f)->s2; + o = nil; + while(f != nil) { + t = f->link; + if((f->flags & Bjo) != 0 && f->first->s2 != f->first) { + changedest(f->first, h, 1); + bexcise(f); + } + else { + f->link = o; + o = f; + } + f = t; + } + s->ents = o; + } + else { + o = nil; + p = nil; + while(f != nil) { + t = f->link; + if((f->flags & (Bpre|Bpin)) != 0 || (f->last->link == R)) { + f->link = p; + p = f; + } + else { + f->link = o; + o = f; + } + f = t; + } + if(o == nil) { + diag(Z, "all Bpre"); + return; + } + if(p == nil) { + p = o; + o = p->link; + p->link = nil; + s->ents = p; + } + else + s->ents = p; + + h = p->first; + // oblit o list repl with jmp to h + while(o != nil) { + changedest(o->first, h, 1); + bexcise(o); + o = o->link; + } + + bbsrecalc(s); + } +} + +static void +iterate(void) +{ + BBset *s; + BB *b, *t; + + heapn = 0; + + for(;;) { + for(b = wounded; b != nil; b = t) { + t = b->link; + enterbb(b); + } + wounded = nil; + + for(s = recalc; s != nil; s = s->link) + calcdamage(s); + recalc = nil; + + if(heapn == 0) + return; + + s = heap[1]; + heapremove(s); + process(s); + } +} + +static void +cleanup(void) +{ + int i; + BB *l, *n; + BBset *b, *t; + + for(i = 0; i < BBHASH; i++) { + b = bbhash[i]; + bbhash[i] = nil; + while(b != nil) { + t = b->next; + bsfree(b); + b = t; + } + } + for(i = 0; i < bcount; i++) + bfree(ordered[i]); + for(l = bbaux; l != nil; l = n) { + n = l->aux; + bfree(l); + } + bbaux = nil; +} + +static void +prreg(Reg *r) +{ + Prog *p; + + p = r->prog; + if(p->to.type == D_BRANCH) + p->to.offset = r->s2->rpo; + print("%ld:%P\tr %lX ", r->rpo, r->prog, r->regu); + print("p1 %ld p2 %ld p2l %ld s1 %ld s2 %ld link %ld", + Rn(r->p1), Rn(r->p2), Rn(r->p2link), + Rn(r->s1), Rn(r->s2), Rn(r->link)); + if(!r->active) + print(" d"); +// print(" %p %p\n", r->prog, r->prog->link); + print("\n"); +} + +static void prfunc(char*); + +static void +checkr(int d) +{ + Prog *p; + Reg *r, *t; + + for(r = firstr; r->link != R; r = r->link) { + for(p = r->prog->link; p != P && p != r->link->prog; p = p->link) + ; + if(p == P) { + print("%ld: bad prog link\n", r->rpo); + if(d) + prfunc(nil); + abort(); + } + if(r->s1 != R && (r->s1 != r->link || r->link->p1 != r)) { + print("%ld: bad s1 p1\n", r->rpo); + if(d) + prfunc(nil); + abort(); + } + if(r->s2 != R && r->s2->p2 == nil) { + print("%ld: no p2 for s2\n", r->rpo); + if(d) + prfunc(nil); + abort(); + } + if(r->p2 != R) { + t = r->p2->s2; + while(t != r) { + t = t->p2link; + if(t == R) { + print("%ld: bad s2 for p2\n", r->rpo); + if(d) + prfunc(nil); + abort(); + } + } + } + } +} + +static void +prfunc(char *s) +{ + Reg *r; + + if(s != nil) + print("%s structure %s\n", s, firstr->prog->from.sym->name); + for(r = firstr; r != R; r = r->link) + prreg(r); + if(s != nil) { + print("end\n"); + checkr(0); + } +} + +/* find p in r's list and replace with l */ +static void +adjprog(Reg *r, Prog *p, Prog *l) +{ + Prog *t, **n; + + for(n = &r->prog->link; (t = *n) != nil; n = &t->link) { + if(t == p) { + *n = l; + return; + } + } + print("adjprog botch\n"); + abort(); +} + +static void +jumptojump(void) +{ + Reg *r; + + for(r = firstr; r != R; r = r->link) { + if(r->prog->as == AJMP && r->p2 != R && r->s2 != r) { + if(bdebug) + print("jump as dest %ld -> %ld\n", r->rpo, r->s2->rpo); + changedest(r, r->s2, 0); + bchange++; + } + } +} + +/* drag a tail to replace a jump. seems to be a bad idea. */ +static void +rearrange(void) +{ + int i; + Reg *j, *t; + BB *b, *p, *s; + + for(i = 0; i < bcount; i++) { + b = ordered[i]; + if(b->flags & Bdel) + continue; + j = b->last; + if(j->prog->as == AJMP && j->s2->p1 == R) { + t = j->s2; + if(t == b->first) + continue; + s = findset(t->rpo); + if(s == nil) { + diag(Z, "no self"); + continue; + } + if(s == ordered[0]) + continue; + if(s->flags & Bdel) + continue; + if(s->last->link == R) + continue; + if(bdebug) + print("drag %ld to %ld\n", t->rpo, j->rpo); + p = findset(t->rpo - 1); + if(p == nil) { + diag(Z, "no predec"); + continue; + } + if(p->last->link != t) { + diag(Z, "bad predec %ld %ld", p->last->rpo, t->rpo); + continue; + } + + /* poison everything in sight */ + b->flags |= Bdel; + s->flags |= Bdel; + findset(j->link->rpo)->flags |= Bdel; + findset(s->last->link->rpo)->flags |= Bdel; + + /* remove */ + adjprog(p->last, t->prog, s->last->link->prog); + p->last->link = s->last->link; + + /* fix tail */ + adjprog(s->last, s->last->link->prog, j->link->prog); + s->last->link = j->link; + + /* fix head */ + adjprog(j, j->link->prog, t->prog); + j->link = t; + + /* nop the jump */ + j->prog->as = ANOP; + j->prog->to.type = D_NONE; + j->s2 = nil; + j->link->p2 = delset(j, j->link->p2); + j->s1 = t; + t->p1 = j; + if(bcheck) + checkr(1); + bchange++; + } + } +} + +void +jumptodot(void) +{ + Reg *r; + + for(r = firstr; r != R; r = r->link) { + if(r->prog->as == AJMP && r->s2 == r->link) { + if(debug['v']) + print("jump to next %ld\n", r->rpo); + r->prog->as = ANOP; + r->prog->to.type = D_NONE; + r->s2 = nil; + r->link->p2 = delset(r, r->link->p2); + findset(r->rpo)->flags |= Bdel; + findset(r->link->rpo)->flags |= Bdel; + bchange++; + } + } +} + +void +comtarg(void) +{ + int n; + BB *b, *c; + Reg *r, *l, *p, *t; + +loop: + bchange = 0; + + /* excise NOPS because they just get in the way */ + /* some have p2 because they are excised labelled moves */ + + if(debug['v']) { + n = 0; + for(r = firstr; r != R; r = r->link) + r->rpo = n++; + prfunc("prenop"); + } + + r = firstr; + l = r->link; + while(l != R) { + if(l->prog->as == ANOP) { + t = l->p1; + p = l->p2; +if(dbg) print("nop %ld [", l->rpo); +if(dbg) printbl(p); + for(;;) { + adjprog(r, l->prog, l->prog->link); + r->link = l->link; + l->link = freer; + freer = l; + l = r->link; + if(l->prog->as != ANOP) + break; +if(dbg) print("] %ld [", l->rpo); +if(dbg) printbl(l->p2); + if(p == R) + p = l->p2; + else if(l->p2 != nil) + appset(l->p2, p); + } +if(dbg) print("] %ld [", l->rpo); +if(dbg) printbl(l->p2); + if(p != R) { + redest(p, l); + if(l->p2 != R) + appset(p, l->p2); + else + l->p2 = p; + } +if(dbg) print("] -> ["); +if(dbg) printbl(l->p2); +if(dbg) print("]\n"); + if(r->s1 != R) + r->s1 = l; + l->p1 = t; + } + r = l; + l = r->link; + } + + n = 0; + for(r = firstr; r != R; r = r->link) + r->rpo = n++; + + if(debug['v']) + prfunc("input"); + + firstbb = nil; + lastbb = nil; + + if(debug['v']) + print("bbstart\n"); + + n = 0; + r = firstr; + do { + b = bba(); + b->first = r; + for(;;) { + l = r; + r = r->link; + switch(l->prog->as) { + case ARET: + case AJMP: + case AIRETL: + goto out; + } + if(r->p2 != R) + break; + } + out: + b->last = l; + if(lastbb == nil) + firstbb = b; + else + lastbb->link = b; + lastbb = b; + if(bdebug) + print("BB %ld %ld\n", b->first->rpo, b->last->rpo); + n++; + } while(r != R); + + if(debug['v']) + print("end\n"); + + if(n > bsize) { + bsize = n * 3 / 2; + if(bsize < BBINIT) + bsize = BBINIT; + ordered = alloc(bsize * sizeof(*ordered)); + heap = alloc((bsize + 1) * sizeof(*ordered)); + } + + if(debug['v']) + print("preprocstart\n"); + + n = 0; + for(b = firstbb; b != nil; b = c) { + c = b->link; + preproc(b, n++); + } + + if(debug['v']) + print("end\n"); + + bcount = n; + + jumptojump(); + + if(debug['v']) + print("iteratestart\n"); + + iterate(); +//checktails(); + + if(debug['v']) + print("end\n"); + + if(debug['v']) + print("extrastart\n"); + + jumptodot(); +// rearrange(); + + if(debug['v']) + print("end\n"); + + cleanup(); + if(bballoc || bbsalloc) + diag(Z, "bballoc %d %d", bballoc, bbsalloc); + + if(debug['v']) + prfunc("output"); + + if(1 && bchange) + goto loop; +} |