/* 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