#include "all.h" static intiscon(Ref r, int64_t bits, Fn *fn){ return rtype(r) == RCon && fn->con[r.val].type == CBits && fn->con[r.val].bits.i == bits;} static intiscopy(Ins *i, Ref r, Fn *fn){ static bits extcpy[] = { [WFull] = 0, [Wsb] = BIT(Wsb) | BIT(Wsh) | BIT(Wsw), [Wub] = BIT(Wub) | BIT(Wuh) | BIT(Wuw), [Wsh] = BIT(Wsh) | BIT(Wsw), [Wuh] = BIT(Wuh) | BIT(Wuw), [Wsw] = BIT(Wsw), [Wuw] = BIT(Wuw), }; bits b; Tmp *t; switch (i->op) { case Ocopy: return 1; case Omul: case Odiv: case Oudiv: return iscon(i->arg[1], 1, fn); case Oadd: case Osub: case Oor: case Oxor: case Osar: case Oshl: case Oshr: return iscon(i->arg[1], 0, fn); default: break; } if (!isext(i->op) || rtype(r) != RTmp) return 0; if (i->op == Oextsw || i->op == Oextuw) if (i->cls == Kw) return 1; t = &fn->tmp[r.val]; assert(KBASE(t->cls) == 0); if (i->cls == Kl && t->cls == Kw) return 0; b = extcpy[t->width]; return (BIT(Wsb + (i->op-Oextsb)) & b) != 0;} static Refcopyof(Ref r, Ref *cpy){ if (rtype(r) == RTmp && !req(cpy[r.val], R)) return cpy[r.val]; return r;} /* detects a cluster of phis/copies redundant with 'r'; * the algorithm is inspired by Section 3.2 of "Simple * and Efficient SSA Construction" by Braun M. et al. */static voidphisimpl(Phi *p, Ref r, Ref *cpy, Use ***pstk, BSet *ts, BSet *as, Fn *fn){ Use **stk, *u, *u1, use = {0}; uint nstk, a; int t; Ref r1; Phi *p0, phi; bszero(ts); bszero(as); memset(&phi, 0, sizeof(phi)); p0 = φ stk = *pstk; nstk = 1; use.type = UPhi; use.u.phi = p; stk[0] = &use; while (nstk) { u = stk[--nstk]; if (u->type == UIns && iscopy(u->u.ins, r, fn)) { p = p0; t = u->u.ins->to.val; } else if (u->type == UPhi) { p = u->u.phi; t = p->to.val; } else continue; if (bshas(ts, t)) continue; bsset(ts, t); for (a=0; a<p->narg; a++) { r1 = copyof(p->arg[a], cpy); if (req(r1, r)) continue; if (rtype(r1) != RTmp) return; bsset(as, r1.val); } u = fn->tmp[t].use; u1 = &u[fn->tmp[t].nuse]; vgrow(pstk, nstk+(u1-u)); stk = *pstk; for (; u<u1; u++) stk[nstk++] = u; } bsdiff(as, ts); if (!bscount(as)) for (t=0; bsiter(ts, &t); t++) cpy[t] = r;} static voidsubst(Ref *pr, Ref *cpy){ assert(rtype(*pr) != RTmp || !req(cpy[pr->val], R)); *pr = copyof(*pr, cpy);} /* requires use and dom, breaks use */voidcopy(Fn *fn){ BSet ts[1], as[1]; Use **stk; Phi *p, **pp; Ins *i; Blk *b; uint n, a, eq; Ref *cpy, r, r1; int t; bsinit(ts, fn->ntmp); bsinit(as, fn->ntmp); cpy = emalloc(fn->ntmp * sizeof cpy[0]); stk = vnew(10, sizeof stk[0], PHeap); /* 1. build the copy-of map */ for (n=0; n<fn->nblk; n++) { b = fn->rpo[n]; for (p=b->phi; p; p=p->link) { assert(rtype(p->to) == RTmp); if (!req(cpy[p->to.val], R)) continue; eq = 0; r = R; for (a=0; a<p->narg; a++) if (p->blk[a]->id < n) { r1 = copyof(p->arg[a], cpy); if (req(r, R) || req(r, UNDEF)) r = r1; if (req(r1, r) || req(r1, UNDEF)) eq++; } assert(!req(r, R)); if (rtype(r) == RTmp && !dom(fn->rpo[fn->tmp[r.val].bid], b)) cpy[p->to.val] = p->to; else if (eq == p->narg) cpy[p->to.val] = r; else { cpy[p->to.val] = p->to; phisimpl(p, r, cpy, &stk, ts, as, fn); } } for (i=b->ins; i<&b->ins[b->nins]; i++) { assert(rtype(i->to) <= RTmp); if (!req(cpy[i->to.val], R)) continue; r = copyof(i->arg[0], cpy); if (iscopy(i, r, fn)) cpy[i->to.val] = r; else cpy[i->to.val] = i->to; } } /* 2. remove redundant phis/copies * and rewrite their uses */ for (b=fn->start; b; b=b->link) { for (pp=&b->phi; (p=*pp);) { r = cpy[p->to.val]; if (!req(r, p->to)) { *pp = p->link; continue; } for (a=0; a<p->narg; a++) subst(&p->arg[a], cpy); pp=&p->link; } for (i=b->ins; i<&b->ins[b->nins]; i++) { r = cpy[i->to.val]; if (!req(r, i->to)) { memset(i, 0, sizeof(*i)); i->op = Onop; continue; } subst(&i->arg[0], cpy); subst(&i->arg[1], cpy); } subst(&b->jmp.arg, cpy); } if (debug['C']) { fprintf(stderr, "\n> Copy information:"); for (t=Tmp0; t<fn->ntmp; t++) { if (req(cpy[t], R)) { fprintf(stderr, "\n%10s not seen!", fn->tmp[t].name); } else if (!req(cpy[t], TMP(t))) { fprintf(stderr, "\n%10s copy of ", fn->tmp[t].name); printref(cpy[t], fn, stderr); } } fprintf(stderr, "\n\n> After copy elimination:\n"); printfn(fn, stderr); } vfree(stk); free(cpy);}
#include "all.h"
static int
iscon(Ref r, int64_t bits, Fn *fn)
{
return rtype(r) == RCon
&& fn->con[r.val].type == CBits
&& fn->con[r.val].bits.i == bits;
}
static int
iscopy(Ins *i, Ref r, Fn *fn)
{
static bits extcpy[] = {
[WFull] = 0,
[Wsb] = BIT(Wsb) | BIT(Wsh) | BIT(Wsw),
[Wub] = BIT(Wub) | BIT(Wuh) | BIT(Wuw),
[Wsh] = BIT(Wsh) | BIT(Wsw),
[Wuh] = BIT(Wuh) | BIT(Wuw),
[Wsw] = BIT(Wsw),
[Wuw] = BIT(Wuw),
};
bits b;
Tmp *t;
switch (i->op) {
case Ocopy:
return 1;
case Omul:
case Odiv:
case Oudiv:
return iscon(i->arg[1], 1, fn);
case Oadd:
case Osub:
case Oor:
case Oxor:
case Osar:
case Oshl:
case Oshr:
return iscon(i->arg[1], 0, fn);
default:
break;
}
if (!isext(i->op) || rtype(r) != RTmp)
return 0;
if (i->op == Oextsw || i->op == Oextuw)
if (i->cls == Kw)
return 1;
t = &fn->tmp[r.val];
assert(KBASE(t->cls) == 0);
if (i->cls == Kl && t->cls == Kw)
return 0;
b = extcpy[t->width];
return (BIT(Wsb + (i->op-Oextsb)) & b) != 0;
}
static Ref
copyof(Ref r, Ref *cpy)
{
if (rtype(r) == RTmp && !req(cpy[r.val], R))
return cpy[r.val];
return r;
}
/* detects a cluster of phis/copies redundant with 'r';
* the algorithm is inspired by Section 3.2 of "Simple
* and Efficient SSA Construction" by Braun M. et al.
*/
static void
phisimpl(Phi *p, Ref r, Ref *cpy, Use ***pstk, BSet *ts, BSet *as, Fn *fn)
{
Use **stk, *u, *u1, use = {0};
uint nstk, a;
int t;
Ref r1;
Phi *p0, phi;
bszero(ts);
bszero(as);
memset(&phi, 0, sizeof(phi));
p0 = φ
stk = *pstk;
nstk = 1;
use.type = UPhi;
use.u.phi = p;
stk[0] = &use;
while (nstk) {
u = stk[--nstk];
if (u->type == UIns && iscopy(u->u.ins, r, fn)) {
p = p0;
t = u->u.ins->to.val;
}
else if (u->type == UPhi) {
p = u->u.phi;
t = p->to.val;
}
else
continue;
if (bshas(ts, t))
continue;
bsset(ts, t);
for (a=0; a<p->narg; a++) {
r1 = copyof(p->arg[a], cpy);
if (req(r1, r))
continue;
if (rtype(r1) != RTmp)
return;
bsset(as, r1.val);
}
u = fn->tmp[t].use;
u1 = &u[fn->tmp[t].nuse];
vgrow(pstk, nstk+(u1-u));
stk = *pstk;
for (; u<u1; u++)
stk[nstk++] = u;
}
bsdiff(as, ts);
if (!bscount(as))
for (t=0; bsiter(ts, &t); t++)
cpy[t] = r;
}
static void
subst(Ref *pr, Ref *cpy)
{
assert(rtype(*pr) != RTmp || !req(cpy[pr->val], R));
*pr = copyof(*pr, cpy);
}
/* requires use and dom, breaks use */
void
copy(Fn *fn)
{
BSet ts[1], as[1];
Use **stk;
Phi *p, **pp;
Ins *i;
Blk *b;
uint n, a, eq;
Ref *cpy, r, r1;
int t;
bsinit(ts, fn->ntmp);
bsinit(as, fn->ntmp);
cpy = emalloc(fn->ntmp * sizeof cpy[0]);
stk = vnew(10, sizeof stk[0], PHeap);
/* 1. build the copy-of map */
for (n=0; n<fn->nblk; n++) {
b = fn->rpo[n];
for (p=b->phi; p; p=p->link) {
assert(rtype(p->to) == RTmp);
if (!req(cpy[p->to.val], R))
continue;
eq = 0;
r = R;
for (a=0; a<p->narg; a++)
if (p->blk[a]->id < n) {
r1 = copyof(p->arg[a], cpy);
if (req(r, R) || req(r, UNDEF))
r = r1;
if (req(r1, r) || req(r1, UNDEF))
eq++;
}
assert(!req(r, R));
if (rtype(r) == RTmp
&& !dom(fn->rpo[fn->tmp[r.val].bid], b))
cpy[p->to.val] = p->to;
else if (eq == p->narg)
cpy[p->to.val] = r;
else {
cpy[p->to.val] = p->to;
phisimpl(p, r, cpy, &stk, ts, as, fn);
}
}
for (i=b->ins; i<&b->ins[b->nins]; i++) {
assert(rtype(i->to) <= RTmp);
if (!req(cpy[i->to.val], R))
continue;
r = copyof(i->arg[0], cpy);
if (iscopy(i, r, fn))
cpy[i->to.val] = r;
else
cpy[i->to.val] = i->to;
}
}
/* 2. remove redundant phis/copies
* and rewrite their uses */
for (b=fn->start; b; b=b->link) {
for (pp=&b->phi; (p=*pp);) {
r = cpy[p->to.val];
if (!req(r, p->to)) {
*pp = p->link;
continue;
}
for (a=0; a<p->narg; a++)
subst(&p->arg[a], cpy);
pp=&p->link;
}
for (i=b->ins; i<&b->ins[b->nins]; i++) {
r = cpy[i->to.val];
if (!req(r, i->to)) {
memset(i, 0, sizeof(*i));
i->op = Onop;
continue;
}
subst(&i->arg[0], cpy);
subst(&i->arg[1], cpy);
}
subst(&b->jmp.arg, cpy);
}
if (debug['C']) {
fprintf(stderr, "\n> Copy information:");
for (t=Tmp0; t<fn->ntmp; t++) {
if (req(cpy[t], R)) {
fprintf(stderr, "\n%10s not seen!",
fn->tmp[t].name);
}
else if (!req(cpy[t], TMP(t))) {
fprintf(stderr, "\n%10s copy of ",
fn->tmp[t].name);
printref(cpy[t], fn, stderr);
}
}
fprintf(stderr, "\n\n> After copy elimination:\n");
printfn(fn, stderr);
}
vfree(stk);
free(cpy);
}