/* 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 dce.cc /// @brief Dead Code Elimination: mark-and-sweep starting from side-effect / control flow roots. /// /// See docs/dce.md for architectural notes. #include "rcc/all.h" #include namespace rcc { namespace { bool is_root(uint op) { if (isstore(op)) return true; if (isalloc(op)) return true; if (ispar(op)) return true; if (isarg(op)) return true; if (op == Ocall) return true; if (op == Oblit0 || op == Oblit1) return true; if (op == Ovastart || op == Ovaarg) return true; if (op == Odbgloc) return true; if (op == Osel0 || op == Osel1) return true; return false; } } // namespace void dce(Ctx*, Fn* fn) { int ntmp = fn->ntmp; std::vector phi_def(static_cast(ntmp), nullptr); std::vector ins_def(static_cast(ntmp), nullptr); for (Blk* b = fn->start; b; b = b->link) { for (Phi* p = b->phi; p; p = p->link) if (rtype(p->to) == RTmp && p->to.val < static_cast(ntmp)) phi_def[p->to.val] = p; for (uint k = 0; k < b->nins; k++) { Ins* i = &b->ins[k]; if (rtype(i->to) == RTmp && i->to.val < static_cast(ntmp)) ins_def[i->to.val] = i; } } std::vector alive(static_cast(ntmp), 0); std::vector wl; auto mark = [&](Ref r) { if (rtype(r) == RTmp && r.val < static_cast(ntmp) && !alive[r.val]) { alive[r.val] = 1; wl.push_back(r.val); } }; for (Blk* b = fn->start; b; b = b->link) { for (uint k = 0; k < b->nins; k++) { Ins* i = &b->ins[k]; if (is_root(i->op)) { mark(i->arg[0]); mark(i->arg[1]); } } mark(b->jmp.arg); } while (!wl.empty()) { uint t = wl.back(); wl.pop_back(); if (Ins* d = ins_def[t]) { mark(d->arg[0]); mark(d->arg[1]); continue; } if (Phi* p = phi_def[t]) { for (uint a = 0; a < p->narg; a++) mark(p->arg[a]); } } int killed_ins = 0, killed_phi = 0; for (Blk* b = fn->start; b; b = b->link) { Phi** pp = &b->phi; while (*pp) { Phi* p = *pp; bool dead = (rtype(p->to) == RTmp && p->to.val < static_cast(ntmp) && !alive[p->to.val]); if (dead) { *pp = p->link; killed_phi++; } else { pp = &p->link; } } uint w = 0; for (uint k = 0; k < b->nins; k++) { Ins* i = &b->ins[k]; if (i->op == Onop) { killed_ins++; continue; } bool root = is_root(i->op); bool has_to = (rtype(i->to) == RTmp && i->to.val < static_cast(ntmp)); if (!root && has_to && !alive[i->to.val]) { killed_ins++; continue; } if (w != k) b->ins[w] = *i; w++; } b->nins = w; } if (debug['D']) { fprintf(stderr, "\n> DCE for %s: killed %d ins, %d phi\n", fn->name, killed_ins, killed_phi); } } } // namespace rcc