diff options
Diffstat (limited to 'alias.c')
-rw-r--r-- | alias.c | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/alias.c b/alias.c new file mode 100644 index 0000000..3d1d00c --- /dev/null +++ b/alias.c @@ -0,0 +1,154 @@ +#include "all.h" + +static void +getalias(Alias *a, Ref r, Fn *fn) +{ + Con *c; + + switch (rtype(r)) { + default: + die("unreachable"); + case RTmp: + *a = fn->tmp[r.val].alias; + assert(a->type != ABot); + break; + case RCon: + c = &fn->con[r.val]; + if (c->type == CAddr) { + a->type = ASym; + strcpy(a->label, c->label); + } else + a->type = ACon; + a->offset = c->bits.i; + break; + } +} + +int +alias(Ref p, int sp, Ref q, int sq, int *delta, Fn *fn) +{ + Alias ap, aq; + int ovlap; + + getalias(&ap, p, fn); + getalias(&aq, q, fn); + *delta = ap.offset - aq.offset; + ovlap = ap.offset < aq.offset + sq && aq.offset < ap.offset + sp; + + if (ap.type & aq.type & 1) { + /* if both are offsets of the same + * stack slot, they alias iif they + * overlap */ + if (req(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 (strcmp(ap.label, aq.label) != 0) + return MayAlias; + if (ovlap) + return MustAlias; + return NoAlias; + } + + if ((ap.type == ACon && aq.type == ACon) + || (ap.type == aq.type && req(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) +{ + if (rtype(r) != RTmp) + return 1; + return fn->tmp[r.val].alias.type != ALoc; +} + +static void +esc(Ref r, Fn *fn) +{ + Alias *a; + + assert(rtype(r) <= RType); + if (rtype(r) == RTmp) { + a = &fn->tmp[r.val].alias; + assert(a->type != ABot); + if (a->type == ALoc) + a->type = AEsc; + } +} + +void +fillalias(Fn *fn) +{ + int n; + Blk *b; + Phi *p; + Ins *i; + Alias *a, a0, a1; + + 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; + a->offset = 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; + else + a->type = AUnk; + a->base = i->to; + a->offset = 0; + } + 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 (!isload(i->op)) + esc(i->arg[0], fn); + if (!isstore(i->op)) + esc(i->arg[1], fn); + } + } + esc(b->jmp.arg, fn); + } +} |