| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 |
- #include "all.h"
- Ref con01[2];
- static inline uint
- mix(uint x0, uint x1)
- {
- return x0 + 17*x1;
- }
- static inline uint
- rhash(Ref r)
- {
- return mix(r.type, r.val);
- }
- static uint
- ihash(Ins *i)
- {
- uint h;
- h = mix(i->op, i->cls);
- h = mix(h, rhash(i->arg[0]));
- h = mix(h, rhash(i->arg[1]));
- return h;
- }
- static int
- ieq(Ins *ia, Ins *ib)
- {
- if (ia->op == ib->op)
- if (ia->cls == ib->cls)
- if (req(ia->arg[0], ib->arg[0]))
- if (req(ia->arg[1], ib->arg[1]))
- return 1;
- return 0;
- }
- static Ins **gvntbl;
- static uint gvntbln;
- static Ins *
- gvndup(Ins *i, int insert)
- {
- uint idx, n;
- Ins *ii;
- idx = ihash(i) % gvntbln;
- for (n=1;; n++) {
- ii = gvntbl[idx];
- if (!ii)
- break;
- if (ieq(i, ii))
- return ii;
- idx++;
- if (gvntbln <= idx)
- idx = 0;
- }
- if (insert)
- gvntbl[idx] = i;
- return 0;
- }
- static void
- replaceuse(Fn *fn, Use *u, Ref r1, Ref r2)
- {
- Blk *b;
- Ins *i;
- Phi *p;
- Ref *pr;
- Tmp *t2;
- int n;
- t2 = 0;
- if (rtype(r2) == RTmp)
- t2 = &fn->tmp[r2.val];
- b = fn->rpo[u->bid];
- switch (u->type) {
- case UPhi:
- p = u->u.phi;
- for (pr=p->arg; pr<&p->arg[p->narg]; pr++)
- if (req(*pr, r1))
- *pr = r2;
- if (t2)
- adduse(t2, UPhi, b, p);
- break;
- case UIns:
- i = u->u.ins;
- for (n=0; n<2; n++)
- if (req(i->arg[n], r1))
- i->arg[n] = r2;
- if (t2)
- adduse(t2, UIns, b, i);
- break;
- case UJmp:
- if (req(b->jmp.arg, r1))
- b->jmp.arg = r2;
- if (t2)
- adduse(t2, UJmp, b);
- break;
- case UXXX:
- die("unreachable");
- }
- }
- static void
- replaceuses(Fn *fn, Ref r1, Ref r2)
- {
- Tmp *t1;
- Use *u;
- assert(rtype(r1) == RTmp);
- t1 = &fn->tmp[r1.val];
- for (u=t1->use; u<&t1->use[t1->nuse]; u++)
- replaceuse(fn, u, r1, r2);
- t1->nuse = 0;
- }
- static void
- dedupphi(Fn *fn, Blk *b)
- {
- Phi *p, **pp;
- Ref r;
- for (pp=&b->phi; (p=*pp);) {
- r = phicopyref(fn, b, p);
- if (!req(r, R)) {
- replaceuses(fn, p->to, r);
- p->to = R;
- *pp = p->link;
- } else
- pp = &p->link;
- }
- }
- static int
- rcmp(Ref a, Ref b)
- {
- if (rtype(a) != rtype(b))
- return rtype(a) - rtype(b);
- return a.val - b.val;
- }
- static void
- normins(Fn *fn, Ins *i)
- {
- uint n;
- int64_t v;
- Ref r;
- /* truncate constant bits to
- * 32 bits for s/w uses */
- for (n=0; n<2; n++) {
- if (!KWIDE(argcls(i, n)))
- if (isconbits(fn, i->arg[n], &v))
- if ((v & 0xffffffff) != v)
- i->arg[n] = getcon(v & 0xffffffff, fn);
- }
- /* order arg[0] <= arg[1] for
- * commutative ops, preferring
- * RTmp in arg[0] */
- if (optab[i->op].commutes)
- if (rcmp(i->arg[0], i->arg[1]) > 0) {
- r = i->arg[1];
- i->arg[1] = i->arg[0];
- i->arg[0] = r;
- }
- }
- static int
- negcon(int cls, Con *c)
- {
- static Con z = {.type = CBits, .bits.i = 0};
- return foldint(c, Osub, cls, &z, c);
- }
- static void
- assoccon(Fn *fn, Blk *b, Ins *i1)
- {
- Tmp *t2;
- Ins *i2;
- int op, fail;
- Con c, c1, c2;
- op = i1->op;
- if (op == Osub)
- op = Oadd;
- if (!optab[op].assoc
- || KBASE(i1->cls) != 0
- || rtype(i1->arg[0]) != RTmp
- || rtype(i1->arg[1]) != RCon)
- return;
- c1 = fn->con[i1->arg[1].val];
- t2 = &fn->tmp[i1->arg[0].val];
- if (t2->def == 0)
- return;
- i2 = t2->def;
- if (op != (i2->op == Osub ? Oadd : i2->op)
- || rtype(i2->arg[1]) != RCon)
- return;
- c2 = fn->con[i2->arg[1].val];
- assert(KBASE(i2->cls) == 0);
- assert(KWIDE(i2->cls) >= KWIDE(i1->cls));
- if (i1->op == Osub && negcon(i1->cls, &c1))
- return;
- if (i2->op == Osub && negcon(i2->cls, &c2))
- return;
- if (foldint(&c, op, i1->cls, &c1, &c2))
- return;
- if (op == Oadd && c.type == CBits)
- if ((i1->cls == Kl && c.bits.i < 0)
- || (i1->cls == Kw && (int32_t)c.bits.i < 0)) {
- fail = negcon(i1->cls, &c);
- assert(fail == 0);
- op = Osub;
- }
- i1->op = op;
- i1->arg[0] = i2->arg[0];
- i1->arg[1] = newcon(&c, fn);
- adduse(&fn->tmp[i1->arg[0].val], UIns, b, i1);
- }
- static void
- killins(Fn *fn, Ins *i, Ref r)
- {
- replaceuses(fn, i->to, r);
- *i = (Ins){.op = Onop};
- }
- static void
- dedupins(Fn *fn, Blk *b, Ins *i)
- {
- Ref r;
- Ins *i1;
- normins(fn, i);
- if (i->op == Onop || pinned(i))
- return;
- /* when sel instructions are inserted
- * before gvn, we may want to optimize
- * them here */
- assert(i->op != Osel0);
- assert(!req(i->to, R));
- assoccon(fn, b, i);
- r = copyref(fn, b, i);
- if (!req(r, R)) {
- killins(fn, i, r);
- return;
- }
- r = foldref(fn, i);
- if (!req(r, R)) {
- killins(fn, i, r);
- return;
- }
- i1 = gvndup(i, 1);
- if (i1) {
- killins(fn, i, i1->to);
- return;
- }
- }
- int
- cmpeqz(Fn *fn, Ref r, Ref *arg, int *cls, int *eqval)
- {
- Ins *i;
- if (rtype(r) != RTmp)
- return 0;
- i = fn->tmp[r.val].def;
- if (i)
- if (optab[i->op].cmpeqwl)
- if (req(i->arg[1], CON_Z)) {
- *arg = i->arg[0];
- *cls = argcls(i, 0);
- *eqval = optab[i->op].eqval;
- return 1;
- }
- return 0;
- }
- static int
- branchdom(Fn *fn, Blk *bif, Blk *bbr1, Blk *bbr2, Blk *b)
- {
- assert(bif->jmp.type == Jjnz);
- if (b != bif
- && dom(bbr1, b)
- && !reachesnotvia(fn, bbr2, b, bif))
- return 1;
- return 0;
- }
- static int
- domzero(Fn *fn, Blk *d, Blk *b, int *z)
- {
- if (branchdom(fn, d, d->s1, d->s2, b)) {
- *z = 0;
- return 1;
- }
- if (branchdom(fn, d, d->s2, d->s1, b)) {
- *z = 1;
- return 1;
- }
- return 0;
- }
- /* infer 0/non-0 value from dominating jnz */
- int
- zeroval(Fn *fn, Blk *b, Ref r, int cls, int *z)
- {
- Blk *d;
- Ref arg;
- int cls1, eqval;
- for (d=b->idom; d; d=d->idom) {
- if (d->jmp.type != Jjnz)
- continue;
- if (req(r, d->jmp.arg)
- && cls == Kw
- && domzero(fn, d, b, z)) {
- return 1;
- }
- if (cmpeqz(fn, d->jmp.arg, &arg, &cls1, &eqval)
- && req(r, arg)
- && cls == cls1
- && domzero(fn, d, b, z)) {
- *z ^= eqval;
- return 1;
- }
- }
- return 0;
- }
- static int
- usecls(Use *u, Ref r, int cls)
- {
- int k;
- switch (u->type) {
- case UIns:
- k = Kx; /* widest use */
- if (req(u->u.ins->arg[0], r))
- k = argcls(u->u.ins, 0);
- if (req(u->u.ins->arg[1], r))
- if (k == Kx || !KWIDE(k))
- k = argcls(u->u.ins, 1);
- return k == Kx ? cls : k;
- case UPhi:
- if (req(u->u.phi->to, R))
- return cls; /* eliminated */
- return u->u.phi->cls;
- case UJmp:
- return Kw;
- default:
- break;
- }
- die("unreachable");
- }
- static void
- propjnz0(Fn *fn, Blk *bif, Blk *s0, Blk *snon0, Ref r, int cls)
- {
- Blk *b;
- Tmp *t;
- Use *u;
- if (s0->npred != 1 || rtype(r) != RTmp)
- return;
- t = &fn->tmp[r.val];
- for (u=t->use; u<&t->use[t->nuse]; u++) {
- b = fn->rpo[u->bid];
- /* we may compare an l temp with a w
- * comparison; so check that the use
- * does not involve high bits */
- if (usecls(u, r, cls) == cls)
- if (branchdom(fn, bif, s0, snon0, b))
- replaceuse(fn, u, r, CON_Z);
- }
- }
- static void
- dedupjmp(Fn *fn, Blk *b)
- {
- Blk **ps;
- int64_t v;
- Ref arg;
- int cls, eqval, z;
- if (b->jmp.type != Jjnz)
- return;
- /* propagate jmp arg as 0 through s2 */
- propjnz0(fn, b, b->s2, b->s1, b->jmp.arg, Kw);
- /* propagate cmp eq/ne 0 def of jmp arg as 0 */
- if (cmpeqz(fn, b->jmp.arg, &arg, &cls, &eqval)) {
- ps = (Blk*[]){b->s1, b->s2};
- propjnz0(fn, b, ps[eqval^1], ps[eqval], arg, cls);
- }
- /* collapse trivial/constant jnz to jmp */
- v = 1;
- z = 0;
- if (b->s1 == b->s2
- || isconbits(fn, b->jmp.arg, &v)
- || zeroval(fn, b, b->jmp.arg, Kw, &z)) {
- if (v == 0 || z)
- b->s1 = b->s2;
- /* we later move active ins out of dead blks */
- b->s2 = 0;
- b->jmp.type = Jjmp;
- b->jmp.arg = R;
- }
- }
- static void
- rebuildcfg(Fn *fn)
- {
- uint n, nblk;
- Blk *b, *s, **rpo;
- Ins *i;
- nblk = fn->nblk;
- rpo = emalloc(nblk * sizeof rpo[0]);
- memcpy(rpo, fn->rpo, nblk * sizeof rpo[0]);
- fillcfg(fn);
- /* move instructions that were in
- * killed blocks and may be active
- * in the computation in the start
- * block */
- s = fn->start;
- for (n=0; n<nblk; n++) {
- b = rpo[n];
- if (b->id != -1u)
- continue;
- /* blk unreachable after GVN */
- assert(b != s);
- for (i=b->ins; i<&b->ins[b->nins]; i++)
- if (!optab[i->op].pinned)
- if (gvndup(i, 0) == i)
- addins(&s->ins, &s->nins, i);
- }
- free(rpo);
- }
- /* requires rpo pred ssa use
- * recreates rpo preds
- * breaks pred use dom ssa (GCM fixes ssa)
- */
- void
- gvn(Fn *fn)
- {
- Blk *b;
- Phi *p;
- Ins *i;
- uint n, nins;
- con01[0] = getcon(0, fn);
- con01[1] = getcon(1, fn);
- /* copy.c uses the visit bit */
- for (b=fn->start; b; b=b->link)
- for (p=b->phi; p; p=p->link)
- p->visit = 0;
- fillloop(fn);
- narrowpars(fn);
- filluse(fn);
- ssacheck(fn);
- nins = 0;
- for (b=fn->start; b; b=b->link) {
- b->visit = 0;
- nins += b->nins;
- }
- gvntbln = nins + nins/2;
- gvntbl = emalloc(gvntbln * sizeof gvntbl[0]);
- for (n=0; n<fn->nblk; n++) {
- b = fn->rpo[n];
- dedupphi(fn, b);
- for (i=b->ins; i<&b->ins[b->nins]; i++)
- dedupins(fn, b, i);
- dedupjmp(fn, b);
- }
- rebuildcfg(fn);
- free(gvntbl);
- gvntbl = 0;
- if (debug['G']) {
- fprintf(stderr, "\n> After GVN:\n");
- printfn(fn, stderr);
- }
- }
|