diff options
| author | 2025-12-20 17:42:30 +0100 | |
|---|---|---|
| committer | 2025-12-20 17:42:30 +0100 | |
| commit | 771554e39c047eec8e0451c5d8d7adbf990d356c (patch) | |
| tree | cf9b10f44a6cd451746dd519684c6c646c951b87 | |
| parent | 96779975f3b8c73e6e1f1e5a07c8c2e386f353ae (diff) | |
backend: general simplification pass skeleton
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | ir/ir.c | 5 | ||||
| -rw-r--r-- | ir/ir.h | 4 | ||||
| -rw-r--r-- | ir/simpl.c | 146 |
4 files changed, 155 insertions, 2 deletions
@@ -1,5 +1,5 @@ SRC=main.c io.c mem.c c/c.c c/lex.c c/eval.c c/builtin.c type.c targ.c \ - ir/ir.c ir/builder.c ir/fold.c ir/dump.c ir/ssa.c ir/cfg.c ir/intrin.c ir/abi0.c ir/mem2reg.c ir/regalloc.c \ + ir/ir.c ir/builder.c ir/fold.c ir/dump.c ir/ssa.c ir/cfg.c ir/intrin.c ir/abi0.c ir/mem2reg.c ir/regalloc.c ir/simpl.c \ x86_64/sysv.c x86_64/isel.c x86_64/emit.c obj/obj.c obj/elf.c \ embedfilesdir.c CFLAGS=-Wall -std=c11 -pedantic @@ -221,7 +221,7 @@ addpred(struct block *blk, struct block *p) xbpush(&blk->_pred, &blk->npred, p); } -static void +void delpred(struct block *blk, struct block *p) { for (int i = 0; i < blk->npred; ++i) { @@ -640,6 +640,9 @@ irfini(struct function *fn) mem2reg(fn); copyopt(fn); } + if (ccopt.o >= OPT1) { + simpl(fn); + } if (ccopt.dbg.o) { bfmt(ccopt.dbgout, "<< Before isel >>\n"); irdump(fn); @@ -275,6 +275,7 @@ void filluses(struct function *); void delinstr(struct block *, int idx); void delphi(struct block *, int idx); void delnops(struct block *blk); +void delpred(struct block *blk, struct block *p); void fillblkids(struct function *); #define startbbvisit() (void)(++visitmark) #define wasvisited(blk) ((blk)->visit == visitmark) @@ -311,6 +312,9 @@ void filldom(struct function *fn); void abi0(struct function *); void abi0_call(struct function *, struct instr *, struct block *blk, int *curi); +/** simpl.c **/ +void simpl(struct function *); + /** mem2reg.c **/ void mem2reg(struct function *); diff --git a/ir/simpl.c b/ir/simpl.c new file mode 100644 index 0000000..fb89c07 --- /dev/null +++ b/ir/simpl.c @@ -0,0 +1,146 @@ +#include "ir.h" + +static int +ins(struct function *fn, struct instr *ins, struct block *blk, int *curi) +{ + int narg = opnarg[ins->op]; + if ((oisarith(ins->op) || oiscmp(ins->op)) && isnumcon(ins->l) && (narg == 1 || isnumcon(ins->r))) { + bool ok; + if (narg == 1) ok = foldunop(&ins->l, ins->op, ins->cls, ins->l); + else ok = foldbinop(&ins->l, ins->op, ins->cls, ins->l, ins->r); + if (!ok) return 0; /* could be div/0 */ + ins->op = Ocopy; + ins->cls = insrescls(*ins); + ins->r = NOREF; + return 1; + } + return 0; +} + +static void +jmpfind(struct block **final, struct block **pblk) +{ + struct block **p2 = &final[(*pblk)->id]; + if (*p2 && !(*p2)->phi.n) { + jmpfind(final, p2); + *pblk = *p2; + } +} + +static void +fillpredsrec(struct block *blk) +{ + while (blk && !wasvisited(blk)) { + markvisited(blk); + if (!blk->s1) return; + if (!blk->s1->phi.n) addpred(blk->s1, blk); + if (!blk->s2) { + blk = blk->s1; + continue; + } + if (!blk->s2->phi.n) addpred(blk->s2, blk); + fillpredsrec(blk->s1); + blk = blk->s2; + } +} + +static void +fillpreds(struct function *fn) +{ + struct block *blk = fn->entry, *next; + do { + if (blk->phi.n) continue; + if (blk->npred > 1) + xbfree(blk->_pred); + blk->npred = 0; + blk->_pred = NULL; + } while ((blk = blk->lnext) != fn->entry); + startbbvisit(); + fillpredsrec(fn->entry); + blk = fn->entry->lnext; + do { /* remove dead blocks */ + next = blk->lnext; + if (!blk->npred) freeblk(fn, blk); + } while ((blk = next) != fn->entry); +} + +void +simpl(struct function *fn) +{ + FREQUIRE(FNUSE); + int inschange = 0, + blkchange = 0; + struct block **jmpfinal = xcalloc(fn->nblk * sizeof *jmpfinal); + struct block *blk = fn->entry; + + do { + for (int i = 0; i < blk->phi.n; ++i) { + + } + for (int i = 0; i < blk->ins.n; ++i) { + inschange += ins(fn, &instrtab[blk->ins.p[i]], blk, &i); + } + + /* merge blocks: + * @blk: + * ... (1) + * b @s + * @s: + * ... (2) + * b {...} + *=> + * @blk: + * ... (1) + * ... (2) + * b {...} + * */ + if (blk != fn->entry) while (blk->s1 && !blk->s2 && blk->s1->npred == 1 && !blk->phi.n) { + struct block *s = blk->s1; + vpushn(&blk->ins, s->ins.p, s->ins.n); + blk->jmp = blk->s1->jmp; + for (int i = 0; i < 2; ++i) { + struct block *ss = (&s->s1)[i]; + if (ss) for (int j = 0; j < ss->npred; ++j) { + if (blkpred(ss, j) == s) { + blkpred(ss, j) = blk; + break; + } + } + } + /* breaks use for temps used in s */ + if (s->ins.n || s->jmp.arg[0].t == RTMP || s->jmp.arg[1].t == RTMP) + fn->prop &= ~FNUSE; + blk->s1 = s->s1; + blk->s2 = s->s2; + freeblk(fn, s); + } + /* thread jumps.. */ + if (!blk->phi.n && !blk->ins.n) { + if (blk->jmp.t == Jb && !blk->s2) { + jmpfind(jmpfinal, &blk->s1); + if (blk->s1 != blk) { + ++blkchange; + jmpfinal[blk->id] = blk->s1; + } + } + } + } while ((blk = blk->lnext) != fn->entry); + if (inschange) { + if (!(fn->prop & FNUSE)) filluses(fn); + copyopt(fn); + } + if (blkchange) { + do { + if (blk->s1) jmpfind(jmpfinal, &blk->s1); + if (blk->s2) jmpfind(jmpfinal, &blk->s2); + if (blk->s1 && blk->s1 == blk->s2) { + memset(blk->jmp.arg, 0, sizeof blk->jmp.arg); + blk->s2 = NULL; + } + } while ((blk = blk->lnext) != fn->entry); + fillpreds(fn); + } + free(jmpfinal); +} + +/* vim:set ts=3 sw=3 expandtab: */ |