aboutsummaryrefslogtreecommitdiffhomepage
path: root/ir/mem2reg.c
diff options
context:
space:
mode:
Diffstat (limited to 'ir/mem2reg.c')
-rw-r--r--ir/mem2reg.c97
1 files changed, 39 insertions, 58 deletions
diff --git a/ir/mem2reg.c b/ir/mem2reg.c
index 0bd78ca..4b0b007 100644
--- a/ir/mem2reg.c
+++ b/ir/mem2reg.c
@@ -65,7 +65,7 @@ deltrivialphis(struct ssabuilder *sb, int var, struct block *blk, union ref phir
/* recursively try to remove all phi users as they might have become trivial */
Redo:
- for (struct use *use = instruse[phiref.i], *uend = use + instrnuse[phiref.i]; use < uend; ++use) {
+ for (struct use *use = instruse[phiref.i]; use; use = use->next) {
if (use->u != USERJUMP && instrtab[use->u].op == Ophi && use->u != phiref.i) {
union ref it = mkref(RTMP, use->u);
union ref vphi2 = deltrivialphis(sb, var, use->blk, it);
@@ -210,14 +210,14 @@ blkfindins(struct block *blk, int ins)
}
static int
-cmpuse(const void *a, const void *b)
+rcmpuse(const void *a, const void *b)
{
- const struct use *ua = a, *ub = b;
+ /* postorder sort */
+ const struct use *ua = *(struct use **)a, *ub = *(struct use **)b;
struct block *blk = ua->blk;
- if (ua->blk != ub->blk) return ua->blk->id - ub->blk->id;
- if (ua->u == USERJUMP) return ub->u != USERJUMP;
- if (ub->u == USERJUMP) return -(ua->u != USERJUMP);
- return blkfindins(blk, ua->u) - blkfindins(blk, ub->u);
+ if (ua->blk != ub->blk) return ub->blk->id - ua->blk->id;
+ assert(ua->u != USERJUMP && ub->u != USERJUMP);
+ return blkfindins(blk, ub->u) - blkfindins(blk, ua->u);
}
void
@@ -234,75 +234,56 @@ mem2reg(struct function *fn)
struct block *blk = fn->entry;
do {
for (int i = 0; i < blk->ins.n; ++i) {
- struct use *use, *uend;
enum irclass k = 0;
- int sz = 0, ndef = 0;
+ int sz = 0;
enum op ext = Ocopy;
int var = blk->ins.p[i];
struct instr *ins = &instrtab[var];
+ struct use *use;
- if (!oisalloca(ins->op)) continue;
- uend = instruse[var] + instrnuse[var];
- for (use = instruse[var]; use < uend; ++use) {
- struct instr *m;
-
- if (use->u == USERJUMP) goto Next;
- m = &instrtab[use->u];
+ /* find allocas only used in loads/stores of uniform size */
+ if (!oisalloca(ins->op) || !(use = instruse[var])) continue;
+ struct use *usesbuf[64];
+ vec_of(struct use *) uses = VINIT(usesbuf, countof(usesbuf));
+ do {
+ if (use->u == USERJUMP) goto Skip;
+ struct instr *m = &instrtab[use->u];
if (oisload(m->op) && (!sz || sz == loadsz(m->op))) {
sz = loadsz(m->op);
k = loadcls(m->op);
if (sz < 4) ext = load2ext(m->op);
- continue;
- }
- if (oisstore(m->op) && m->l.bits == mkref(RTMP, var).bits
- && (!sz || sz == storesz(m->op))) {
+ } else if (oisstore(m->op) && m->l.bits == mkref(RTMP, var).bits
+ && (!sz || sz == storesz(m->op))) {
sz = storesz(m->op);
- ++ndef;
- continue;
- }
- goto Next;
- }
- if (!ndef && instrnuse[var] > 0) /* slot is read from but never written to */
- goto Next;
+ } else goto Skip;
+ vpush(&uses, use);
+ } while ((use = use->next));
- qsort(instruse[var], instrnuse[var], sizeof *instruse[var], cmpuse);
- for (use = instruse[var]; use < uend; ++use) {
- struct instr *m = &instrtab[use->u];
+ /* visit uses in rpo */
+ qsort(uses.p, uses.n, sizeof *uses.p, rcmpuse);
+ for (int i = uses.n-1; i >= 0; --i) {
+ use = uses.p[i];
+ ins = &instrtab[use->u];
- if (oisstore(m->op)) {
- writevar(&sb, var, use->blk, m->r);
- *m = mkinstr(Onop,0,);
- } else if (oisload(m->op)) {
- union ref val = readvar(&sb, var, k = m->cls, use->blk);
- if (!val.bits) { /* var is used uninitialized */
- /* TODO emit diagnostic */
- /* load some garbage */
- *m = mkinstr(kisflt(k) ? Oloadf32 + (k==KF64) : Oloads8+ilog2(sz)*2,
- k, mkref(RREG, mctarg->bpr));
- } else {
- adduse(use->blk, use->u, val);
- if (isintcon(val) && ext != Ocopy) {
- vlong x = intconval(val);
- switch (ext) {
- case Oexts8: x = (schar)x; break;
- case Oextu8: x = (uchar)x; break;
- case Oexts16: x = (short)x; break;
- case Oextu16: x = (ushort)x; break;
- case Oexts32: x = (int)x; break;
- case Oextu32: x = (uint)x; break;
- default: assert(0);
- }
- val = mkintcon(k, x);
- ext = Ocopy;
- }
- *m = mkinstr(ext, k, val);
+ if (oisstore(ins->op)) {
+ writevar(&sb, var, use->blk, ins->r);
+ *ins = mkinstr(Onop,0,);
+ } else if (oisload(ins->op)) {
+ union ref val = readvar(&sb, var, k = ins->cls, use->blk);
+ adduse(use->blk, use->u, val);
+ if (ext != Ocopy && isintcon(val)) { /* fold constant int extension */
+ val = irunop(NULL, ext, k, val);
+ assert(val.bits);
+ ext = Ocopy;
}
+ *ins = mkinstr(ext, k, val);
}
}
/* remove alloca */
delinstr(blk, i--);
- Next:;
+ Skip:
+ vfree(&uses);
}
assert(sb.lastvisit == blk->id);