diff options
| author | Quentin Carbonneaux <[email protected]> | 2026-01-13 18:15:01 +0100 |
|---|---|---|
| committer | Quentin Carbonneaux <[email protected]> | 2026-01-13 18:17:35 +0100 |
| commit | e8365dd0a2cb3050b62e9cb263e1a9a09481d76f (patch) | |
| tree | 0ed63c3a0f6c3b47b1bd09fd0d64fc8336118d53 /cfg.c | |
| parent | c6336557dad1161088c3f60a8045d676fb924ed5 (diff) | |
new simplcfg pass
Useful for ifopt to match more
often. Empty blocks are fused
and conditional jumps on empty
blocks with the same successor
(and no phis in the successor)
are collapsed.
Diffstat (limited to 'cfg.c')
| -rw-r--r-- | cfg.c | 121 |
1 files changed, 121 insertions, 0 deletions
@@ -441,3 +441,124 @@ ifgraph(Blk *ifb, Blk **pthenb, Blk **pelseb, Blk **pjoinb) *pjoinb = s1->s1; return 1; } + +typedef struct Jmp Jmp; + +struct Jmp { + int type; + Ref arg; + Blk *s1, *s2; +}; + +static int +jmpeq(Jmp *a, Jmp *b) +{ + return a->type == b->type && req(a->arg, b->arg) + && a->s1 == b->s1 && a->s2 == b->s2; +} + +static int +jmpnophi(Jmp *j) +{ + if (j->s1 && j->s1->phi) + return 0; + if (j->s2 && j->s2->phi) + return 0; + return 1; +} + +/* require cfg rpo, breaks use */ +void +simplcfg(Fn *fn) +{ + Ins cpy, *i; + Blk *b, *bb, **pb; + Jmp *jmp, *j, *jj; + Phi *p; + int *empty, done; + uint n; + + if (debug['C']) { + fprintf(stderr, "\n> Before CFG simplification:\n"); + printfn(fn, stderr); + } + + cpy = (Ins){.op = Ocopy}; + for (b=fn->start; b; b=b->link) + if (b->npred == 1) { + bb = b->pred[0]; + for (p=b->phi; p; p=p->link) { + cpy.cls = p->cls; + cpy.to = p->to; + cpy.arg[0] = phiarg(p, bb); + addins(&bb->ins, &bb->nins, &cpy); + } + b->phi = 0; + } + + jmp = emalloc(fn->nblk * sizeof jmp[0]); + empty = emalloc(fn->nblk * sizeof empty[0]); + for (b=fn->start; b; b=b->link) { + jmp[b->id].type = b->jmp.type; + jmp[b->id].arg = b->jmp.arg; + jmp[b->id].s1 = b->s1; + jmp[b->id].s2 = b->s2; + empty[b->id] = !b->phi; + for (i=b->ins; i<&b->ins[b->nins]; i++) + if (i->op != Onop || i->op != Odbgloc) { + empty[b->id] = 0; + break; + } + } + + do { + done = 1; + for (b=fn->start; b; b=b->link) { + if (b->id == -1u) + continue; + j = &jmp[b->id]; + if (j->type == Jjmp && j->s1->npred == 1) { + assert(!j->s1->phi); + addbins(&b->ins, &b->nins, j->s1); + empty[b->id] &= empty[j->s1->id]; + jj = &jmp[j->s1->id]; + pb = (Blk*[]){jj->s1, jj->s2, 0}; + for (; (bb=*pb); pb++) + for (p=bb->phi; p; p=p->link) { + n = phiargn(p, j->s1); + p->blk[n] = b; + } + j->s1->id = -1u; + *j = *jj; + done = 0; + } + else if (j->type == Jjnz + && empty[j->s1->id] && empty[j->s2->id] + && jmpeq(&jmp[j->s1->id], &jmp[j->s2->id]) + && jmpnophi(&jmp[j->s1->id])) { + *j = jmp[j->s1->id]; + done = 0; + } + } + } while (!done); + + for (b=fn->start; b; b=b->link) + if (b->id != -1u) { + j = &jmp[b->id]; + b->jmp.type = j->type; + b->jmp.arg = j->arg; + b->s1 = j->s1; + b->s2 = j->s2; + assert(!j->s1 || j->s1->id != -1u); + assert(!j->s2 || j->s2->id != -1u); + } + + fillcfg(fn); + free(empty); + free(jmp); + + if (debug['C']) { + fprintf(stderr, "\n> After CFG simplification:\n"); + printfn(fn, stderr); + } +} |
