From 2b1f6c1e2cc22eef6d1a7cdc1c852fddf534fcc7 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Mon, 8 Jun 2026 17:06:35 +0800 Subject: [legacy/mid] Add control-flow optimization: if-conversion --- rcc-legacy/src/mid/ifopt.cc | 127 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 rcc-legacy/src/mid/ifopt.cc (limited to 'rcc-legacy/src') diff --git a/rcc-legacy/src/mid/ifopt.cc b/rcc-legacy/src/mid/ifopt.cc new file mode 100644 index 0000000..c82fb4c --- /dev/null +++ b/rcc-legacy/src/mid/ifopt.cc @@ -0,0 +1,127 @@ +/* Source code for RCC-Legacy. + Copyright (C) 2026 Richard Qin + +This file is part of RCC. + +RCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +RCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with RCC; see the file LICENSE. If not see +. */ + +/// @file ifopt.cc +/// @brief If-conversion: collapses if-then[-else] diamond CFG into straight-line block + sel +/// instructions. +/// +/// See docs/ifopt.md for architectural notes. + +#include "rcc/all.h" + +namespace rcc { + +namespace { + +enum { + MaxIns = 2, + MaxPhis = 2, +}; + +bool okbranch(Blk* b) { + int n = 0; + for (Ins* i = b->ins; i < &b->ins[b->nins]; ++i) { + if (i->op == Odbgloc) + continue; + if (pinned(i)) + return false; + if (i->op != Onop) + ++n; + } + return n <= MaxIns; +} + +bool okjoin(Blk* b) { + int n = 0; + for (Phi* p = b->phi; p; p = p->link) { + if (KBASE(p->cls) != 0) + return false; + ++n; + } + return n <= MaxPhis; +} + +bool okgraph(Blk* ifb, Blk* thenb, Blk* elseb, Blk* joinb) { + assert(thenb != elseb); + return joinb->npred == 2 && okjoin(joinb) && (thenb == ifb || okbranch(thenb)) && + (elseb == ifb || okbranch(elseb)); +} + +void convert(Ctx* ctx, Blk* ifb, Blk* thenb, Blk* elseb, Blk* joinb) { + Ins* ins = static_cast(vnew(ctx, 0, sizeof ins[0], PHeap)); + uint nins = 0; + + addbins(ctx, &ins, &nins, ifb); + if (thenb != ifb) + addbins(ctx, &ins, &nins, thenb); + if (elseb != ifb) + addbins(ctx, &ins, &nins, elseb); + + assert(joinb->npred == 2); + Ins sel = {}; + if (joinb->phi) { + sel.op = Osel0; + sel.cls = static_cast(Kw); + sel.arg[0] = ifb->jmp.arg; + addins(ctx, &ins, &nins, &sel); + } + + sel = {}; + sel.op = Osel1; + for (Phi* p = joinb->phi; p; p = p->link) { + sel.to = p->to; + sel.cls = static_cast(p->cls); + sel.arg[0] = phiarg(p, thenb); + sel.arg[1] = phiarg(p, elseb); + addins(ctx, &ins, &nins, &sel); + } + + idup(ctx, ifb, ins, nins); + ifb->jmp.type = Jjmp; + ifb->jmp.arg = Ref::none(); + ifb->s1 = joinb; + ifb->s2 = nullptr; + joinb->npred = 1; + joinb->pred[0] = ifb; + joinb->phi = nullptr; + vfree(ins); +} + +} // namespace + +void ifconvert(Ctx* ctx, Fn* fn) { + if (debug['K']) + fputs("\n> If-conversion:\n", ctx->dbg_buf); + + Blk *thenb, *elseb, *joinb; + for (Blk* ifb = fn->start; ifb; ifb = ifb->link) + if (ifgraph(ifb, &thenb, &elseb, &joinb) && okgraph(ifb, thenb, elseb, joinb)) { + if (debug['K']) + fprintf(ctx->dbg_buf, " @%s -> @%s, @%s -> @%s\n", ifb->name, thenb->name, + elseb->name, joinb->name); + convert(ctx, ifb, thenb, elseb, joinb); + } + + if (debug['K']) { + fprintf(ctx->dbg_buf, "\n> After if-conversion:\n"); + printfn(fn, ctx->dbg_buf); + } +} + +} // namespace rcc -- cgit v1.2.3