libqbe/alias.c
Quentin Carbonneaux bd7a73d0ea fix bug in alias analysis
The handling of phi was incorrect
and we would sometimes miss escapes.
We now handle phis at the very end
of the pass to make sure the defs
for their arguments have all been
processed.
2024-03-07 16:40:51 +01:00

222 lines
4.3 KiB
C

#include "all.h"
void
getalias(Alias *a, Ref r, Fn *fn)
{
Con *c;
switch (rtype(r)) {
default:
die("unreachable");
case RTmp:
*a = fn->tmp[r.val].alias;
if (astack(a->type))
a->type = a->slot->type;
assert(a->type != ABot);
break;
case RCon:
c = &fn->con[r.val];
if (c->type == CAddr) {
a->type = ASym;
a->u.sym = c->sym;
} else
a->type = ACon;
a->offset = c->bits.i;
a->slot = 0;
break;
}
}
int
alias(Ref p, int op, int sp, Ref q, int sq, int *delta, Fn *fn)
{
Alias ap, aq;
int ovlap;
getalias(&ap, p, fn);
getalias(&aq, q, fn);
ap.offset += op;
/* when delta is meaningful (ovlap == 1),
* we do not overflow int because sp and
* sq are bounded by 2^28 */
*delta = ap.offset - aq.offset;
ovlap = ap.offset < aq.offset + sq && aq.offset < ap.offset + sp;
if (astack(ap.type) && astack(aq.type)) {
/* if both are offsets of the same
* stack slot, they alias iif they
* overlap */
if (ap.base == aq.base && ovlap)
return MustAlias;
return NoAlias;
}
if (ap.type == ASym && aq.type == ASym) {
/* they conservatively alias if the
* symbols are different, or they
* alias for sure if they overlap */
if (!symeq(ap.u.sym, aq.u.sym))
return MayAlias;
if (ovlap)
return MustAlias;
return NoAlias;
}
if ((ap.type == ACon && aq.type == ACon)
|| (ap.type == aq.type && ap.base == aq.base)) {
assert(ap.type == ACon || ap.type == AUnk);
/* if they have the same base, we
* can rely on the offsets only */
if (ovlap)
return MustAlias;
return NoAlias;
}
/* if one of the two is unknown
* there may be aliasing unless
* the other is provably local */
if (ap.type == AUnk && aq.type != ALoc)
return MayAlias;
if (aq.type == AUnk && ap.type != ALoc)
return MayAlias;
return NoAlias;
}
int
escapes(Ref r, Fn *fn)
{
Alias *a;
if (rtype(r) != RTmp)
return 1;
a = &fn->tmp[r.val].alias;
return !astack(a->type) || a->slot->type == AEsc;
}
static void
esc(Ref r, Fn *fn)
{
Alias *a;
assert(rtype(r) <= RType);
if (rtype(r) == RTmp) {
a = &fn->tmp[r.val].alias;
if (astack(a->type))
a->slot->type = AEsc;
}
}
static void
store(Ref r, int sz, Fn *fn)
{
Alias *a;
int64_t off;
bits m;
if (rtype(r) == RTmp) {
a = &fn->tmp[r.val].alias;
if (a->slot) {
assert(astack(a->type));
off = a->offset;
if (sz >= NBit
|| (off < 0 || off >= NBit))
m = -1;
else
m = (BIT(sz) - 1) << off;
a->slot->u.loc.m |= m;
}
}
}
void
fillalias(Fn *fn)
{
uint n;
int t, sz;
int64_t x;
Blk *b;
Phi *p;
Ins *i;
Con *c;
Alias *a, a0, a1;
for (t=0; t<fn->ntmp; t++)
fn->tmp[t].alias.type = ABot;
for (n=0; n<fn->nblk; ++n) {
b = fn->rpo[n];
for (p=b->phi; p; p=p->link) {
assert(rtype(p->to) == RTmp);
a = &fn->tmp[p->to.val].alias;
assert(a->type == ABot);
a->type = AUnk;
a->base = p->to.val;
a->offset = 0;
a->slot = 0;
}
for (i=b->ins; i<&b->ins[b->nins]; ++i) {
a = 0;
if (!req(i->to, R)) {
assert(rtype(i->to) == RTmp);
a = &fn->tmp[i->to.val].alias;
assert(a->type == ABot);
if (Oalloc <= i->op && i->op <= Oalloc1) {
a->type = ALoc;
a->slot = a;
a->u.loc.sz = -1;
if (rtype(i->arg[0]) == RCon) {
c = &fn->con[i->arg[0].val];
x = c->bits.i;
if (c->type == CBits)
if (0 <= x && x <= NBit)
a->u.loc.sz = x;
}
} else {
a->type = AUnk;
a->slot = 0;
}
a->base = i->to.val;
a->offset = 0;
}
if (i->op == Ocopy) {
assert(a);
getalias(a, i->arg[0], fn);
}
if (i->op == Oadd) {
getalias(&a0, i->arg[0], fn);
getalias(&a1, i->arg[1], fn);
if (a0.type == ACon) {
*a = a1;
a->offset += a0.offset;
}
else if (a1.type == ACon) {
*a = a0;
a->offset += a1.offset;
}
}
if (req(i->to, R) || a->type == AUnk)
if (i->op != Oblit0) {
if (!isload(i->op))
esc(i->arg[0], fn);
if (!isstore(i->op))
if (i->op != Oargc)
esc(i->arg[1], fn);
}
if (i->op == Oblit0) {
++i;
assert(i->op == Oblit1);
assert(rtype(i->arg[0]) == RInt);
sz = abs(rsval(i->arg[0]));
store((i-1)->arg[1], sz, fn);
}
if (isstore(i->op))
store(i->arg[1], storesz(i), fn);
}
if (b->jmp.type != Jretc)
esc(b->jmp.arg, fn);
}
for (b=fn->start; b; b=b->link)
for (p=b->phi; p; p=p->link)
for (n=0; n<p->narg; n++)
esc(p->arg[n], fn);
}