aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2025-09-15 17:11:05 +0200
committerlemon <lsof@mailbox.org>2025-09-15 17:11:46 +0200
commitb8ae5b14c7bbe28161ea83f4c10045f8af5b766a (patch)
treeb53e99abf48f82435220aecea86c5569b85a74e6
parentbdf9776b0b127b53a34be07f8adc0541df78654e (diff)
mem2reg: fix deltrivialphis bug
-rw-r--r--cfg.c43
-rw-r--r--ir.c9
-rw-r--r--optmem.c21
-rw-r--r--regalloc.c1
4 files changed, 64 insertions, 10 deletions
diff --git a/cfg.c b/cfg.c
new file mode 100644
index 0000000..73c7559
--- /dev/null
+++ b/cfg.c
@@ -0,0 +1,43 @@
+#include "ir.h"
+
+static void
+porec(struct block ***rpo, struct block *b)
+{
+ if (wasvisited(b)) return;
+ markvisited(b);
+ if (b->s2) porec(rpo, b->s2);
+ if (b->s1) porec(rpo, b->s1);
+ *--*rpo = b;
+}
+
+void
+sortrpo(struct function *fn)
+{
+ static struct block **rpobuf;
+ struct block **rpoend, **rpo;
+ int i, ndead;
+
+ xbgrow(&rpobuf, fn->nblk);
+ rpo = rpoend = rpobuf + fn->nblk,
+
+ startbbvisit();
+ fn->entry->id = 0;
+ markvisited(fn->entry);
+ if (fn->entry->s1) porec(&rpo, fn->entry->s1);
+ if (fn->entry->s2) porec(&rpo, fn->entry->s2);
+ *--rpo = fn->entry;
+ ndead = rpo - rpobuf;
+ for (i = 1, ++rpo; rpo < rpoend; ++rpo, ++i) {
+ rpo[-1]->lnext = rpo[0];
+ rpo[0]->lprev = rpo[-1];
+ rpo[0]->id = i;
+ }
+ fn->entry->lprev = rpo[-1];
+ rpo[-1]->lnext = fn->entry;
+ for (rpo = rpobuf; ndead > 0; --ndead) {
+ (*rpo)->lnext = (*rpo)->lprev = NULL;
+ freeblk(fn, *rpo);
+ }
+}
+
+/* vim:set ts=3 sw=3 expandtab: */
diff --git a/ir.c b/ir.c
index b1045b1..834ff45 100644
--- a/ir.c
+++ b/ir.c
@@ -288,7 +288,7 @@ newinstr(void)
assert(ninstr < arraylength(instrtab));
t = ninstr++;
}
- if (instrnuse[t] > arraylength(*instrusebuf))
+ if (instruse[t] != instrusebuf[t])
xbfree(instruse[t]);
instruse[t] = instrusebuf[t];
instrnuse[t] = 0;
@@ -298,8 +298,9 @@ newinstr(void)
void
adduse(struct block *ublk, int ui, union ref r) {
struct use user = { ublk, ui };
+
if (r.t != RTMP) return;
- if (instrnuse[r.i] < arraylength(*instrusebuf)) {
+ if (instrnuse[r.i] < arraylength(instrusebuf[r.i])) {
instruse[r.i][instrnuse[r.i]++] = user;
} else if (instrnuse[r.i] == arraylength(*instrusebuf)) {
struct use *use = NULL;
@@ -416,8 +417,10 @@ replcuses(union ref from, union ref to)
void
deluses(int ins)
{
- if (instrnuse[ins] > 2)
+ if (instruse[ins] != instrusebuf[ins]) {
xbfree(instruse[ins]);
+ instruse[ins] = instrusebuf[ins];
+ }
instrnuse[ins] = 0;
}
diff --git a/optmem.c b/optmem.c
index 00be3a0..9e8d1c6 100644
--- a/optmem.c
+++ b/optmem.c
@@ -43,17 +43,15 @@ deltrivialphis(struct ssabuilder *sb, struct block *blk, union ref phiref)
assert(instrtab[phiref.i].op == Ophi);
- if (phiref.i == 4)
- efmt("");
-
for (int i = 0; i < blk->npred; ++i) {
- if (args[i].bits == same.bits || args[i].bits == phiref.bits)
+ if (args[i].bits == same.bits || args[i].bits == phiref.bits) {
continue; /* unique value or self-reference */
- if (same.bits != 0) {
+ } if (same.bits != 0) {
return phiref; /* non-trivial */
}
same = args[i];
}
+
if (same.bits == 0)
same = UNDREF; /* the phi is unreachable or in the start block */
@@ -78,6 +76,7 @@ Redo:
union ref vphi2 = deltrivialphis(sb, use->blk, it);
if (vphi2.bits != it.bits) {
/* deletion happened so phiref use may have changed */
+ if (same.bits == it.bits) same.bits = vphi2.bits;
goto Redo;
}
}
@@ -106,6 +105,7 @@ writevar(struct ssabuilder *sb, int var, struct block *blk, union ref val)
if (!(pcurdefs = imap_get(&sb->curdefs, var))) {
pcurdefs = imap_set(&sb->curdefs, var, xcalloc(sb->nblk * sizeof(union ref)));
}
+ if (val.t == RTMP) assert(instrtab[val.i].op != Onop);
(*pcurdefs)[blk->id] = val;
}
@@ -144,6 +144,7 @@ trysealrec(struct ssabuilder *sb, struct block *blk)
{
vec_of(struct pendingphi) *pending;
+Recur:
if (bstest(sb->sealed, blk->id)) return 1;
if (blk->id > sb->lastvisit) return 0;
markvisited(blk);
@@ -160,8 +161,14 @@ trysealrec(struct ssabuilder *sb, struct block *blk)
mkref(RTMP, pending->p[i].phi));
}
vfree(pending);
- if (blk->s1) trysealrec(sb, blk->s1);
- if (blk->s2) trysealrec(sb, blk->s2);
+ if (blk->s1 && !blk->s2) {
+ blk = blk->s1;
+ goto Recur;
+ } else if (blk->s1 && blk->s2) {
+ trysealrec(sb, blk->s1);
+ blk = blk->s2;
+ goto Recur;
+ }
return 1;
}
diff --git a/regalloc.c b/regalloc.c
index 2a878d0..1018e7c 100644
--- a/regalloc.c
+++ b/regalloc.c
@@ -33,6 +33,7 @@ readvar(struct bitset *defined, enum irclass cls, int var, struct block *blk)
union ref val;
if (bstest(defined, var)) return mkref(RTMP, var);
+ assert(cls && "?");
/* memoed definition */
if (xbcap(curdefs) > blk->id && xbcap(curdefs[blk->id]) > var && curdefs[blk->id][var])