diff options
| author | 2026-03-17 13:22:00 +0100 | |
|---|---|---|
| committer | 2026-03-17 13:22:00 +0100 | |
| commit | a8d6f8bf30c07edb775e56889f568ca20240bedf (patch) | |
| tree | b5a452b2675b2400f15013617291fe6061180bbf /src/ir_cse.c | |
| parent | 24f14b7ad1af08d872971d72ce089a529911f657 (diff) | |
REFACTOR: move sources to src/
Diffstat (limited to 'src/ir_cse.c')
| -rw-r--r-- | src/ir_cse.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/src/ir_cse.c b/src/ir_cse.c new file mode 100644 index 0000000..23c5cf9 --- /dev/null +++ b/src/ir_cse.c @@ -0,0 +1,92 @@ +#include "ir.h" + +static inline bool +pure(const struct instr *ins) +{ + return oisarith(ins->op) || (oisload(ins->op) && !ins->keep); +} + +static inline bool +insequ(const struct instr *a, const struct instr *b) +{ + if (a->op != b->op) return 0; + enum op op = a->op; + switch (opnarg[op]) { + default: assert(0); + case 2: if (a->r.bits != b->r.bits) return 0; + case 1: if (a->l.bits != b->l.bits) return 0; + } + return 1; +} + +static struct ht { + uint t; + ushort memno, cutoff; + struct block *b; +} *insht; +static uint ninsht; + +static inline size_t +hashins(const struct instr *ins) +{ + return hashb(0, ins, sizeof *ins); +} + +static bool +doms(struct block *blk, struct block *b) +{ + for (;; b = b->idom) { + if (blk == b) return 1; + if (blk == b->idom) return 1; + if (blk->id > b->id) return 0; + } +} + +static int +uniq(int t, struct block *blk, int cutoff, int memno) +{ + assert((uint)t < MAXINSTR); + struct instr *ins = &instrtab[t]; + if (!pure(ins)) return t; + for (size_t h = hashins(&instrtab[t]), i = h;; ++i) { + struct ht *p = &insht[i &= (ninsht-1)]; + if (!p->b) Put: { + p->b = blk; + p->memno = memno; + p->cutoff = cutoff; + return p->t = t; + } else if (insequ(&instrtab[p->t], ins)) { + if (p->cutoff == cutoff && (!oisload(ins->op) || p->memno == memno) && doms(p->b, blk)) + return p->t; + goto Put; + } + } +} + +void +cselim(struct function *fn) +{ + FREQUIRE(FNUSE | FNRPO | FNDOM | FNBLKID); + extern int ninstr; + for (ninsht = 32; ninsht <= ninstr; ninsht *= 2) ; + insht = allocz(fn->passarena, ninsht * sizeof *insht, 0); + int memno = 0, cutoff = 0; + struct block *blk = fn->entry; + do { + ++memno; + for (int i = 0; i < blk->ins.n; ++i) { + int t = blk->ins.p[i], q; + if ((q = uniq(t, blk, cutoff, memno)) != t) { + replcuses(mkref(RTMP, t), mkref(RTMP, q)); + delinstr(blk, i--); + } else if (oisstore(instrtab[t].op)) { + /* assume everything alias everything */ + ++memno; + } else if (instrtab[t].op == Ocall) { + ++cutoff; + } + } + } while ((blk = blk->lnext) != fn->entry); +} + +/* vim:set ts=3 sw=3 expandtab: */ |