|
|
@@ -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);
|
|
|
+ }
|
|
|
+}
|