| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460 |
- #include "all.h"
- #define NOBID (-1u)
- static int
- isdivwl(Ins *i)
- {
- switch (i->op) {
- case Odiv:
- case Orem:
- case Oudiv:
- case Ourem:
- return KBASE(i->cls) == 0;
- default:
- return 0;
- }
- }
- int
- pinned(Ins *i)
- {
- return optab[i->op].pinned || isdivwl(i);
- }
- /* pinned ins that can be eliminated if unused */
- static int
- canelim(Ins *i)
- {
- return isload(i->op) || isalloc(i->op) || isdivwl(i);
- }
- static uint earlyins(Fn *, Blk *, Ins *);
- static uint
- schedearly(Fn *fn, Ref r)
- {
- Tmp *t;
- Blk *b;
- if (rtype(r) != RTmp)
- return 0;
- t = &fn->tmp[r.val];
- if (t->gcmbid != NOBID)
- return t->gcmbid;
- b = fn->rpo[t->bid];
- if (t->def) {
- assert(b->ins <= t->def && t->def < &b->ins[b->nins]);
- t->gcmbid = 0; /* mark as visiting */
- t->gcmbid = earlyins(fn, b, t->def);
- } else {
- /* phis do not move */
- t->gcmbid = t->bid;
- }
- return t->gcmbid;
- }
- static uint
- earlyins(Fn *fn, Blk *b, Ins *i)
- {
- uint b0, b1;
- b0 = schedearly(fn, i->arg[0]);
- assert(b0 != NOBID);
- b1 = schedearly(fn, i->arg[1]);
- assert(b1 != NOBID);
- if (fn->rpo[b0]->depth < fn->rpo[b1]->depth) {
- assert(dom(fn->rpo[b0], fn->rpo[b1]));
- b0 = b1;
- }
- return pinned(i) ? b->id : b0;
- }
- static void
- earlyblk(Fn *fn, uint bid)
- {
- Blk *b;
- Phi *p;
- Ins *i;
- uint n;
- b = fn->rpo[bid];
- for (p=b->phi; p; p=p->link)
- for (n=0; n<p->narg; n++)
- schedearly(fn, p->arg[n]);
- for (i=b->ins; i<&b->ins[b->nins]; i++)
- if (pinned(i)) {
- schedearly(fn, i->arg[0]);
- schedearly(fn, i->arg[1]);
- }
- schedearly(fn, b->jmp.arg);
- }
- /* least common ancestor in dom tree */
- static uint
- lcabid(Fn *fn, uint bid1, uint bid2)
- {
- Blk *b;
- if (bid1 == NOBID)
- return bid2;
- if (bid2 == NOBID)
- return bid1;
- b = lca(fn->rpo[bid1], fn->rpo[bid2]);
- assert(b);
- return b->id;
- }
- static uint
- bestbid(Fn *fn, uint earlybid, uint latebid)
- {
- Blk *curb, *earlyb, *bestb;
- if (latebid == NOBID)
- return NOBID; /* unused */
- assert(earlybid != NOBID);
- earlyb = fn->rpo[earlybid];
- bestb = curb = fn->rpo[latebid];
- assert(dom(earlyb, curb));
- while (curb != earlyb) {
- curb = curb->idom;
- if (curb->loop < bestb->loop)
- bestb = curb;
- }
- return bestb->id;
- }
- static uint lateins(Fn *, Blk *, Ins *, Ref r);
- static uint latephi(Fn *, Phi *, Ref r);
- static uint latejmp(Blk *, Ref r);
- /* return lca bid of ref uses */
- static uint
- schedlate(Fn *fn, Ref r)
- {
- Tmp *t;
- Blk *b;
- Use *u;
- uint earlybid;
- uint latebid;
- uint uselatebid;
- if (rtype(r) != RTmp)
- return NOBID;
- t = &fn->tmp[r.val];
- if (t->visit)
- return t->gcmbid;
- t->visit = 1;
- earlybid = t->gcmbid;
- if (earlybid == NOBID)
- return NOBID; /* not used */
- /* reuse gcmbid for late bid */
- t->gcmbid = t->bid;
- latebid = NOBID;
- for (u=t->use; u<&t->use[t->nuse]; u++) {
- assert(u->bid < fn->nblk);
- b = fn->rpo[u->bid];
- switch (u->type) {
- case UXXX:
- die("unreachable");
- break;
- case UPhi:
- uselatebid = latephi(fn, u->u.phi, r);
- break;
- case UIns:
- uselatebid = lateins(fn, b, u->u.ins, r);
- break;
- case UJmp:
- uselatebid = latejmp(b, r);
- break;
- }
- latebid = lcabid(fn, latebid, uselatebid);
- }
- /* latebid may be NOBID if the temp is used
- * in fixed instructions that may be eliminated
- * and are themselves unused transitively */
- if (t->def && !pinned(t->def))
- t->gcmbid = bestbid(fn, earlybid, latebid);
- /* else, keep the early one */
- /* now, gcmbid is the best bid */
- return t->gcmbid;
- }
- /* returns lca bid of uses or NOBID if
- * the definition can be eliminated */
- static uint
- lateins(Fn *fn, Blk *b, Ins *i, Ref r)
- {
- uint latebid;
- assert(b->ins <= i && i < &b->ins[b->nins]);
- assert(req(i->arg[0], r) || req(i->arg[1], r));
- latebid = schedlate(fn, i->to);
- if (pinned(i)) {
- if (latebid == NOBID)
- if (canelim(i))
- return NOBID;
- return b->id;
- }
- return latebid;
- }
- static uint
- latephi(Fn *fn, Phi *p, Ref r)
- {
- uint n;
- uint latebid;
- if (!p->narg)
- return NOBID; /* marked as unused */
- latebid = NOBID;
- for (n = 0; n < p->narg; n++)
- if (req(p->arg[n], r))
- latebid = lcabid(fn, latebid, p->blk[n]->id);
- assert(latebid != NOBID);
- return latebid;
- }
- static uint
- latejmp(Blk *b, Ref r)
- {
- if (req(b->jmp.arg, R))
- return NOBID;
- else {
- assert(req(b->jmp.arg, r));
- return b->id;
- }
- }
- static void
- lateblk(Fn *fn, uint bid)
- {
- Blk *b;
- Phi **pp;
- Ins *i;
- b = fn->rpo[bid];
- for (pp=&b->phi; *(pp);)
- if (schedlate(fn, (*pp)->to) == NOBID) {
- (*pp)->narg = 0; /* mark unused */
- *pp = (*pp)->link; /* remove phi */
- } else
- pp = &(*pp)->link;
- for (i=b->ins; i<&b->ins[b->nins]; i++)
- if (pinned(i))
- schedlate(fn, i->to);
- }
- static void
- addgcmins(Fn *fn, Ins *vins, uint nins)
- {
- Ins *i;
- Tmp *t;
- Blk *b;
- for (i=vins; i<&vins[nins]; i++) {
- assert(rtype(i->to) == RTmp);
- t = &fn->tmp[i->to.val];
- b = fn->rpo[t->gcmbid];
- addins(&b->ins, &b->nins, i);
- }
- }
- /* move live instructions to the
- * end of their target block; use-
- * before-def errors are fixed by
- * schedblk */
- static void
- gcmmove(Fn *fn)
- {
- Tmp *t;
- Ins *vins, *i;
- uint nins;
- nins = 0;
- vins = vnew(nins, sizeof vins[0], PFn);
- for (t=fn->tmp; t<&fn->tmp[fn->ntmp]; t++) {
- if (t->def == 0)
- continue;
- if (t->bid == t->gcmbid)
- continue;
- i = t->def;
- if (pinned(i) && !canelim(i))
- continue;
- assert(rtype(i->to) == RTmp);
- assert(t == &fn->tmp[i->to.val]);
- if (t->gcmbid != NOBID)
- addins(&vins, &nins, i);
- *i = (Ins){.op = Onop};
- }
- addgcmins(fn, vins, nins);
- }
- /* dfs ordering */
- static Ins *
- schedins(Fn *fn, Blk *b, Ins *i, Ins **pvins, uint *pnins)
- {
- Ins *i0, *i1;
- Tmp *t;
- uint n;
- igroup(b, i, &i0, &i1);
- for (i=i0; i<i1; i++)
- for (n=0; n<2; n++) {
- if (rtype(i->arg[n]) != RTmp)
- continue;
- t = &fn->tmp[i->arg[n].val];
- if (t->bid != b->id || !t->def)
- continue;
- schedins(fn, b, t->def, pvins, pnins);
- }
- for (i=i0; i<i1; i++) {
- addins(pvins, pnins, i);
- *i = (Ins){.op = Onop};
- }
- return i1;
- }
- /* order ins within a block */
- static void
- schedblk(Fn *fn)
- {
- Blk *b;
- Ins *i, *vins;
- uint nins;
- vins = vnew(0, sizeof vins[0], PHeap);
- for (b=fn->start; b; b=b->link) {
- nins = 0;
- for (i=b->ins; i<&b->ins[b->nins];)
- i = schedins(fn, b, i, &vins, &nins);
- idup(b, vins, nins);
- }
- vfree(vins);
- }
- static int
- cheap(Ins *i)
- {
- int x;
- if (KBASE(i->cls) != 0)
- return 0;
- switch (i->op) {
- case Oneg:
- case Oadd:
- case Osub:
- case Omul:
- case Oand:
- case Oor:
- case Oxor:
- case Osar:
- case Oshr:
- case Oshl:
- return 1;
- default:
- return iscmp(i->op, &x, &x);
- }
- }
- static void
- sinkref(Fn *fn, Blk *b, Ref *pr)
- {
- Ins i;
- Tmp *t;
- Ref r;
- if (rtype(*pr) != RTmp)
- return;
- t = &fn->tmp[pr->val];
- if (!t->def
- || t->bid == b->id
- || pinned(t->def)
- || !cheap(t->def))
- return;
- /* sink t->def to b */
- i = *t->def;
- r = newtmp("snk", t->cls, fn);
- t = 0; /* invalidated */
- *pr = r;
- i.to = r;
- fn->tmp[r.val].gcmbid = b->id;
- emiti(i);
- sinkref(fn, b, &i.arg[0]);
- sinkref(fn, b, &i.arg[1]);
- }
- /* redistribute trivial ops to point of
- * use to reduce register pressure
- * requires rpo, use; breaks use
- */
- static void
- sink(Fn *fn)
- {
- Blk *b;
- Ins *i;
- for (b=fn->start; b; b=b->link) {
- for (i=b->ins; i<&b->ins[b->nins]; i++)
- if (isload(i->op))
- sinkref(fn, b, &i->arg[0]);
- else if (isstore(i->op))
- sinkref(fn, b, &i->arg[1]);
- sinkref(fn, b, &b->jmp.arg);
- }
- addgcmins(fn, curi, &insb[NIns] - curi);
- }
- /* requires use dom
- * maintains rpo pred dom
- * breaks use
- */
- void
- gcm(Fn *fn)
- {
- Tmp *t;
- uint bid;
- filldepth(fn);
- fillloop(fn);
- for (t=fn->tmp; t<&fn->tmp[fn->ntmp]; t++) {
- t->visit = 0;
- t->gcmbid = NOBID;
- }
- for (bid=0; bid<fn->nblk; bid++)
- earlyblk(fn, bid);
- for (bid=0; bid<fn->nblk; bid++)
- lateblk(fn, bid);
- gcmmove(fn);
- filluse(fn);
- curi = &insb[NIns];
- sink(fn);
- filluse(fn);
- schedblk(fn);
-
- if (debug['G']) {
- fprintf(stderr, "\n> After GCM:\n");
- printfn(fn, stderr);
- }
- }
|