qbe/cfg.c

335 lines
5 KiB
C
Raw Normal View History

2016-12-05 08:09:48 +01:00
#include "all.h"
Blk *
blknew()
{
static Blk z;
Blk *b;
b = alloc(sizeof *b);
*b = z;
return b;
}
void
edgedel(Blk *bs, Blk **pbd)
2016-12-05 08:09:48 +01:00
{
Blk *bd;
2016-12-05 08:09:48 +01:00
Phi *p;
uint a;
int mult;
2016-12-05 08:09:48 +01:00
bd = *pbd;
mult = 1 + (bs->s1 == bs->s2);
*pbd = 0;
if (!bd || mult > 1)
return;
for (p=bd->phi; p; p=p->link) {
for (a=0; p->blk[a]!=bs; a++)
assert(a+1<p->narg);
p->narg--;
memmove(&p->blk[a], &p->blk[a+1],
sizeof p->blk[0] * (p->narg-a));
memmove(&p->arg[a], &p->arg[a+1],
sizeof p->arg[0] * (p->narg-a));
}
if (bd->npred != 0) {
for (a=0; bd->pred[a]!=bs; a++)
assert(a+1<bd->npred);
bd->npred--;
memmove(&bd->pred[a], &bd->pred[a+1],
sizeof bd->pred[0] * (bd->npred-a));
2016-12-05 08:09:48 +01:00
}
}
static void
addpred(Blk *bp, Blk *bc)
{
if (!bc->pred) {
bc->pred = alloc(bc->npred * sizeof bc->pred[0]);
bc->visit = 0;
}
bc->pred[bc->visit++] = bp;
}
/* fill predecessors information in blocks */
void
fillpreds(Fn *f)
{
Blk *b;
for (b=f->start; b; b=b->link) {
b->npred = 0;
b->pred = 0;
}
for (b=f->start; b; b=b->link) {
if (b->s1)
b->s1->npred++;
if (b->s2 && b->s2 != b->s1)
b->s2->npred++;
}
for (b=f->start; b; b=b->link) {
if (b->s1)
addpred(b, b->s1);
if (b->s2 && b->s2 != b->s1)
addpred(b, b->s2);
}
}
static int
2017-02-06 20:36:27 +01:00
rporec(Blk *b, uint x)
2016-12-05 08:09:48 +01:00
{
Blk *s1, *s2;
2017-02-06 20:36:27 +01:00
if (!b || b->id != -1u)
2016-12-05 08:09:48 +01:00
return x;
b->id = 1;
s1 = b->s1;
s2 = b->s2;
if (s1 && s2 && s1->loop > s2->loop) {
s1 = b->s2;
s2 = b->s1;
}
x = rporec(s1, x);
x = rporec(s2, x);
b->id = x;
2017-02-08 03:56:00 +01:00
assert(x != -1u);
2016-12-05 08:09:48 +01:00
return x - 1;
}
/* fill the rpo information */
void
fillrpo(Fn *f)
{
2017-02-06 20:36:27 +01:00
uint n;
2016-12-05 08:09:48 +01:00
Blk *b, **p;
for (b=f->start; b; b=b->link)
2017-02-06 20:36:27 +01:00
b->id = -1u;
2016-12-05 08:09:48 +01:00
n = 1 + rporec(f->start, f->nblk-1);
f->nblk -= n;
f->rpo = alloc(f->nblk * sizeof f->rpo[0]);
for (p=&f->start; (b=*p);) {
2017-02-06 20:36:27 +01:00
if (b->id == -1u) {
edgedel(b, &b->s1);
edgedel(b, &b->s2);
2016-12-05 08:09:48 +01:00
*p = b->link;
} else {
b->id -= n;
f->rpo[b->id] = b;
p = &b->link;
}
}
}
/* for dominators computation, read
* "A Simple, Fast Dominance Algorithm"
* by K. Cooper, T. Harvey, and K. Kennedy.
*/
static Blk *
inter(Blk *b1, Blk *b2)
{
Blk *bt;
if (b1 == 0)
return b2;
while (b1 != b2) {
if (b1->id < b2->id) {
bt = b1;
b1 = b2;
b2 = bt;
}
while (b1->id > b2->id) {
b1 = b1->idom;
assert(b1);
}
}
return b1;
}
void
filldom(Fn *fn)
{
Blk *b, *d;
2017-02-06 20:36:27 +01:00
int ch;
uint n, p;
2016-12-05 08:09:48 +01:00
for (b=fn->start; b; b=b->link) {
b->idom = 0;
b->dom = 0;
b->dlink = 0;
}
do {
ch = 0;
for (n=1; n<fn->nblk; n++) {
b = fn->rpo[n];
d = 0;
for (p=0; p<b->npred; p++)
if (b->pred[p]->idom
|| b->pred[p] == fn->start)
d = inter(d, b->pred[p]);
if (d != b->idom) {
ch++;
b->idom = d;
}
}
} while (ch);
for (b=fn->start; b; b=b->link)
if ((d=b->idom)) {
assert(d != b);
b->dlink = d->dom;
d->dom = b;
}
}
int
sdom(Blk *b1, Blk *b2)
{
assert(b1 && b2);
if (b1 == b2)
return 0;
while (b2->id > b1->id)
b2 = b2->idom;
return b1 == b2;
}
int
dom(Blk *b1, Blk *b2)
{
return b1 == b2 || sdom(b1, b2);
}
static void
addfron(Blk *a, Blk *b)
{
2017-02-06 20:36:27 +01:00
uint n;
2016-12-05 08:09:48 +01:00
for (n=0; n<a->nfron; n++)
if (a->fron[n] == b)
return;
if (!a->nfron)
2017-01-13 04:31:51 +01:00
a->fron = vnew(++a->nfron, sizeof a->fron[0], Pfn);
2016-12-05 08:09:48 +01:00
else
vgrow(&a->fron, ++a->nfron);
a->fron[a->nfron-1] = b;
}
/* fill the dominance frontier */
void
fillfron(Fn *fn)
{
Blk *a, *b;
for (b=fn->start; b; b=b->link)
b->nfron = 0;
2016-12-05 08:09:48 +01:00
for (b=fn->start; b; b=b->link) {
if (b->s1)
for (a=b; !sdom(a, b->s1); a=a->idom)
addfron(a, b->s1);
if (b->s2)
for (a=b; !sdom(a, b->s2); a=a->idom)
addfron(a, b->s2);
}
}
static void
loopmark(Blk *hd, Blk *b, void f(Blk *, Blk *))
{
uint p;
if (b->id < hd->id || b->visit == hd->id)
return;
b->visit = hd->id;
f(hd, b);
for (p=0; p<b->npred; ++p)
loopmark(hd, b->pred[p], f);
}
void
loopiter(Fn *fn, void f(Blk *, Blk *))
{
2017-02-06 20:36:27 +01:00
uint n, p;
Blk *b;
for (b=fn->start; b; b=b->link)
2017-02-06 20:36:27 +01:00
b->visit = -1u;
for (n=0; n<fn->nblk; ++n) {
b = fn->rpo[n];
for (p=0; p<b->npred; ++p)
if (b->pred[p]->id >= n)
loopmark(b, b->pred[p], f);
}
}
void
multloop(Blk *hd, Blk *b)
{
(void)hd;
b->loop *= 10;
}
void
fillloop(Fn *fn)
{
Blk *b;
for (b=fn->start; b; b=b->link)
b->loop = 1;
loopiter(fn, multloop);
}
static void
2017-02-27 18:01:44 +01:00
uffind(Blk **pb, Blk **uf)
{
Blk **pb1;
pb1 = &uf[(*pb)->id];
2017-02-27 17:54:55 +01:00
if (*pb1) {
2017-02-27 18:01:44 +01:00
uffind(pb1, uf);
2017-02-27 17:54:55 +01:00
*pb = *pb1;
}
}
/* requires rpo and no phis, breaks cfg */
void
simpljmp(Fn *fn)
{
Blk **uf; /* union-find */
Blk **p, *b, *ret;
int c;
ret = blknew();
ret->id = fn->nblk++;
ret->jmp.type = Jret0;
2017-02-27 17:54:55 +01:00
uf = emalloc(fn->nblk * sizeof uf[0]);
for (b=fn->start; b; b=b->link) {
assert(!b->phi);
if (b->jmp.type == Jret0) {
b->jmp.type = Jjmp;
b->s1 = ret;
}
if (b->nins == 0)
if (b->jmp.type == Jjmp) {
uffind(&b->s1, uf);
if (b->s1 != b)
uf[b->id] = b->s1;
}
}
for (p=&fn->start; (b=*p); p=&b->link) {
if (b->s1)
2017-02-27 18:01:44 +01:00
uffind(&b->s1, uf);
if (b->s2)
2017-02-27 18:01:44 +01:00
uffind(&b->s2, uf);
prepare for multi-target This big diff does multiple changes to allow the addition of new targets to qbe. The changes are listed below in decreasing order of impact. 1. Add a new Target structure. To add support for a given target, one has to implement all the members of the Target structure. All the source files where changed to use this interface where needed. 2. Single out amd64-specific code. In this commit, the amd64 target T_amd64_sysv is the only target available, it is implemented in the amd64/ directory. All the non-static items in this directory are prefixed with either amd64_ or amd64_sysv (for items that are specific to the System V ABI). 3. Centralize Ops information. There is now a file 'ops.h' that must be used to store all the available operations together with their metadata. The various targets will only select what they need; but it is beneficial that there is only *one* place to change to add a new instruction. One good side effect of this change is that any operation 'xyz' in the IL now as a corresponding 'Oxyz' in the code. 4. Misc fixes. One notable change is that instruction selection now generates generic comparison operations and the lowering to the target's comparisons is done in the emitter. GAS directives for data are the same for many targets, so data emission was extracted in a file 'gas.c'. 5. Modularize the Makefile. The Makefile now has a list of C files that are target-independent (SRC), and one list of C files per target. Each target can also use its own 'all.h' header (for example to define registers).
2017-04-09 03:06:33 +02:00
c = b->jmp.type - Jjf;
if (0 <= c && c <= NCmp)
if (b->s1 == b->s2) {
b->jmp.type = Jjmp;
b->s2 = 0;
}
}
*p = ret;
2017-02-27 17:54:55 +01:00
free(uf);
}