mirror of
git://c9x.me/qbe.git
synced 2026-05-26 15:34:41 +00:00
Simple Inner Loop Optimzation
Two simple loop optimizations. 1. Strength reduction of mul[tiplication] by loop induction variable. 2. Hoisting of (address) base into phi where loop induction variable is used only as a base (address) offset. Limited to loops with a single body block, which happily is always innermost loops. This restriction would not be very hard to lift - it would require detecting the set of loop blocks (and ensuring reducibility?) Limited to loop induction variables with 0 initial value and increment of 1 (for mul strength reduction). This limitation is trivial to lift; however all of the cproc/hare[c]/coremark opportunity is with 0/1 loops for mul reduction, and 0 initial value for base-offset opt.
This commit is contained in:
parent
ac48f83f17
commit
5370616f7d
4
Makefile
4
Makefile
@ -5,8 +5,8 @@ PREFIX = /usr/local
|
|||||||
BINDIR = $(PREFIX)/bin
|
BINDIR = $(PREFIX)/bin
|
||||||
|
|
||||||
COMMOBJ = main.o util.o parse.o abi.o cfg.o mem.o ssa.o alias.o load.o \
|
COMMOBJ = main.o util.o parse.o abi.o cfg.o mem.o ssa.o alias.o load.o \
|
||||||
copy.o fold.o gvn.o gcm.o simpl.o ifopt.o live.o spill.o rega.o \
|
copy.o fold.o gvn.o gcm.o loopopt.o simpl.o ifopt.o live.o \
|
||||||
emit.o
|
spill.o rega.o emit.o
|
||||||
AMD64OBJ = amd64/targ.o amd64/sysv.o amd64/isel.o amd64/emit.o amd64/winabi.o
|
AMD64OBJ = amd64/targ.o amd64/sysv.o amd64/isel.o amd64/emit.o amd64/winabi.o
|
||||||
ARM64OBJ = arm64/targ.o arm64/abi.o arm64/isel.o arm64/emit.o
|
ARM64OBJ = arm64/targ.o arm64/abi.o arm64/isel.o arm64/emit.o
|
||||||
RV64OBJ = rv64/targ.o rv64/abi.o rv64/isel.o rv64/emit.o
|
RV64OBJ = rv64/targ.o rv64/abi.o rv64/isel.o rv64/emit.o
|
||||||
|
|||||||
3
all.h
3
all.h
@ -606,6 +606,9 @@ void gcm(Fn *);
|
|||||||
/* ifopt.c */
|
/* ifopt.c */
|
||||||
void ifconvert(Fn *fn);
|
void ifconvert(Fn *fn);
|
||||||
|
|
||||||
|
/* loopopt.c */
|
||||||
|
void loopopt(Fn *fn);
|
||||||
|
|
||||||
/* simpl.c */
|
/* simpl.c */
|
||||||
void simpl(Fn *);
|
void simpl(Fn *);
|
||||||
|
|
||||||
|
|||||||
217
loopopt.c
Normal file
217
loopopt.c
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
#include "all.h"
|
||||||
|
|
||||||
|
typedef struct Cntr Cntr;
|
||||||
|
typedef struct Loop Loop;
|
||||||
|
|
||||||
|
static int
|
||||||
|
forloop(Blk *bh, Blk *bb)
|
||||||
|
{
|
||||||
|
if (bh->npred == 2)
|
||||||
|
if (bh->jmp.type == Jjnz)
|
||||||
|
if (bb->npred == 1)
|
||||||
|
if (bb->jmp.type == Jjmp)
|
||||||
|
if (bb->s1 == bh)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
doloop(Blk *bh)
|
||||||
|
{
|
||||||
|
if (bh->npred == 2)
|
||||||
|
if (bh->jmp.type == Jjnz)
|
||||||
|
if (bh->s1 == bh || bh->s2 == bh)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Loop {
|
||||||
|
Blk *bp; /* pre-header */
|
||||||
|
Blk *bh; /* header */
|
||||||
|
Blk *bb; /* body */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
invariant(Ref r, Loop l, Fn *fn)
|
||||||
|
{
|
||||||
|
Tmp *t;
|
||||||
|
|
||||||
|
if (rtype(r) == RCon)
|
||||||
|
return 1;
|
||||||
|
assert(rtype(r) == RTmp);
|
||||||
|
t = &fn->tmp[r.val];
|
||||||
|
if (t->bid != l.bh->id)
|
||||||
|
if (t->bid != l.bb->id)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Cntr {
|
||||||
|
Phi *p; /* defining phi */
|
||||||
|
Ref r0; /* initial value */
|
||||||
|
Ref rc; /* post-increment */
|
||||||
|
Ref ri; /* increment */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* check if a phi defines an additive
|
||||||
|
* induction variable
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
counter(Fn *fn, Loop l, Phi *p, Cntr *c)
|
||||||
|
{
|
||||||
|
Tmp *t;
|
||||||
|
Ins *i;
|
||||||
|
|
||||||
|
assert(l.bh->npred == 2);
|
||||||
|
assert(l.bh->pred[0] == l.bb || l.bh->pred[1] == l.bb);
|
||||||
|
c->p = p;
|
||||||
|
c->r0 = phiarg(p, l.bp);
|
||||||
|
c->rc = phiarg(p, l.bb);
|
||||||
|
if (KBASE(p->cls) != 0
|
||||||
|
|| rtype(c->rc) != RTmp
|
||||||
|
|| (t = &fn->tmp[c->rc.val])->bid != l.bb->id
|
||||||
|
|| !(i = t->def)
|
||||||
|
|| i->op != Oadd
|
||||||
|
|| req(i->arg[0], p->to) == req(i->arg[1], p->to))
|
||||||
|
return 0;
|
||||||
|
c->ri = i->arg[req(i->arg[0], p->to)];
|
||||||
|
assert(p->cls == i->cls);
|
||||||
|
return invariant(c->ri, l, fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mulredux(Fn *fn, Loop l, Cntr c)
|
||||||
|
{
|
||||||
|
Ins *i, *ie, ia;
|
||||||
|
Phi *p;
|
||||||
|
Ref rm;
|
||||||
|
|
||||||
|
/* dead simple case for now...
|
||||||
|
* majority case in practice */
|
||||||
|
if (!req(c.r0, con01[0]) || !req(c.ri, con01[1]))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ia = (Ins){.op = Oadd};
|
||||||
|
ie = &l.bb->ins[l.bb->nins]; /* l.bb->ins may change */
|
||||||
|
for (i=l.bb->ins; i<ie; i++) {
|
||||||
|
/* TODO i->cls != p->cls is not necessary? */
|
||||||
|
if (i->op != Omul
|
||||||
|
|| i->cls != p->cls
|
||||||
|
|| req(i->arg[0], p->to) == req(i->arg[1], p->to))
|
||||||
|
continue;
|
||||||
|
assert(KBASE(i->cls) == 0);
|
||||||
|
rm = i->arg[req(i->arg[0], p->to)];
|
||||||
|
if (!invariant(rm, l, fn))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ia.to = newtmp("lop", i->cls, fn);
|
||||||
|
ia.cls = i->cls;
|
||||||
|
ia.arg[0] = i->to;
|
||||||
|
ia.arg[1] = rm;
|
||||||
|
addins(&l.bb->ins, &l.bb->nins, &ia);
|
||||||
|
p = alloc(sizeof *p);
|
||||||
|
p->cls = i->cls;
|
||||||
|
p->to = i->to;
|
||||||
|
p->narg = 2;
|
||||||
|
p->blk = vnew(2, sizeof p->blk[0], PFn);
|
||||||
|
p->blk[0] = l.bp;
|
||||||
|
p->blk[1] = l.bb;
|
||||||
|
p->arg = vnew(2, sizeof p->arg[0], PFn);
|
||||||
|
p->arg[0] = CON_Z;
|
||||||
|
p->arg[1] = ia.to;
|
||||||
|
p->link = l.bh->phi;
|
||||||
|
l.bh->phi = p;
|
||||||
|
*i = (Ins){.op = Onop};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
addbase(Fn *fn, Loop l, Cntr c)
|
||||||
|
{
|
||||||
|
Ins *i, *ii, *ib;
|
||||||
|
Tmp *t, *ti;
|
||||||
|
Use *u;
|
||||||
|
Ref rb;
|
||||||
|
uint n;
|
||||||
|
|
||||||
|
/* dead simple case for now...
|
||||||
|
* majority case in practice */
|
||||||
|
if (!req(c.r0, CON_Z))
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert(rtype(c.p->to) == RTmp);
|
||||||
|
t = &fn->tmp[c.p->to.val];
|
||||||
|
if (t->nuse != 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ii = ib = 0;
|
||||||
|
for (u=t->use; u<&t->use[t->nuse]; u++) {
|
||||||
|
if (u->type != UIns)
|
||||||
|
return;
|
||||||
|
i = u->u.ins;
|
||||||
|
if (i->op != Oadd
|
||||||
|
|| i->cls != c.p->cls
|
||||||
|
|| u->bid != l.bb->id)
|
||||||
|
return;
|
||||||
|
assert(req(i->arg[0], c.p->to) || req(i->arg[1], c.p->to));
|
||||||
|
if (req(i->to, c.rc)) {
|
||||||
|
assert(rtype(i->to) == RTmp);
|
||||||
|
ti = &fn->tmp[i->to.val];
|
||||||
|
if (ti->nuse != 1)
|
||||||
|
return;
|
||||||
|
assert(ti->use[0].type == UPhi);
|
||||||
|
assert(ti->use[0].bid == l.bh->id);
|
||||||
|
assert(ti->use[0].u.phi == c.p);
|
||||||
|
ii = i;
|
||||||
|
} else {
|
||||||
|
rb = i->arg[req(i->arg[0], c.p->to)];
|
||||||
|
if (!invariant(rb, l, fn))
|
||||||
|
return;
|
||||||
|
assert(!req(rb, c.p->to));
|
||||||
|
ib = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n = phiargn(c.p, l.bp);
|
||||||
|
assert(n != -1u && req(c.p->arg[n], CON_Z));
|
||||||
|
c.p->arg[n] = rb;
|
||||||
|
ii->arg[!req(ii->arg[0], c.p->to)] = ib->to;
|
||||||
|
c.p->to = ib->to;
|
||||||
|
*ib = (Ins){.op = Onop};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
counteropt(Fn *fn, void opt(Fn *, Loop, Cntr))
|
||||||
|
{
|
||||||
|
Loop l;
|
||||||
|
Cntr c;
|
||||||
|
Phi *p;
|
||||||
|
uint n;
|
||||||
|
|
||||||
|
for (n=0; n<fn->nblk; n++) {
|
||||||
|
l.bh = fn->rpo[n];
|
||||||
|
if (forloop(l.bh, l.bh->s1))
|
||||||
|
l.bb = l.bh->s1;
|
||||||
|
else if (forloop(l.bh, l.bh->s2))
|
||||||
|
l.bb = l.bh->s2;
|
||||||
|
else if (doloop(l.bh))
|
||||||
|
l.bb = l.bh; /* header and body */
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
l.bp = l.bh->pred[l.bh->pred[0] == l.bh];
|
||||||
|
assert(l.bh->loop > 1);
|
||||||
|
assert(l.bh->loop == l.bb->loop);
|
||||||
|
for (p=l.bh->phi; p; p=p->link)
|
||||||
|
if (counter(fn, l, p, &c)) {
|
||||||
|
assert(KBASE(p->cls) == 0);
|
||||||
|
opt(fn, l, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
loopopt(Fn *fn)
|
||||||
|
{
|
||||||
|
counteropt(fn, mulredux);
|
||||||
|
filluse(fn);
|
||||||
|
counteropt(fn, addbase);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user