/* 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 ssa.cc
/// @brief Use chain population / SSA construction (Cytron-style) / SSA invariant validation.
///
/// See docs/ssa.md for architectural notes.
#include "rcc/all.h"
namespace rcc {
// Use chain append
namespace {
inline void use_append(Ctx* ctx, Tmp* tmp, decltype(Use::type) ty, Blk* b, Phi* phi, Ins* ins) {
if (!tmp->use)
return;
uint n = tmp->nuse++;
vgrow(ctx, &tmp->use, tmp->nuse);
Use* u = &tmp->use[n];
u->type = ty;
u->bid = b->id;
if (ty == Use::UPhi)
u->u.phi = phi;
else if (ty == Use::UIns)
u->u.ins = ins;
// UJmp has no extra payload
}
} // namespace
void adduse_ins(Ctx* ctx, Tmp* tmp, Blk* b, Ins* ins) {
use_append(ctx, tmp, Use::UIns, b, nullptr, ins);
}
void adduse_phi(Ctx* ctx, Tmp* tmp, Blk* b, Phi* phi) {
use_append(ctx, tmp, Use::UPhi, b, phi, nullptr);
}
void adduse_jmp(Ctx* ctx, Tmp* tmp, Blk* b) {
use_append(ctx, tmp, Use::UJmp, b, nullptr, nullptr);
}
// filluse - Recompute def / use / cls / width / phi-equiv-class for each tmp
namespace {
/// Derive width from def instruction op (sub-word width info, for spill storage selection).
int derive_width(Ins* i) {
int op = i->op;
if (isparbh(op))
return Tmp::Wsb + (op - Oparsb);
if (isload(op) && op != Oload)
return Tmp::Wsb + (op - Oloadsb);
if (isext(op))
return Tmp::Wsb + (op - Oextsb);
int kx, cx;
if (iscmp(op, &kx, &cx))
return Tmp::Wub;
return Tmp::WFull;
}
} // namespace
void filluse(Ctx* ctx, Fn* fn) {
Tmp* tmp = fn->tmp;
// Reset metadata for each user tmp; first call creates empty vnew head for use[].
for (int t = Tmp0; t < fn->ntmp; t++) {
tmp[t].def = nullptr;
tmp[t].bid = ~0u;
tmp[t].ndef = 0;
tmp[t].nuse = 0;
tmp[t].cls = 0;
tmp[t].phi = 0;
tmp[t].width = Tmp::WFull;
if (!tmp[t].use)
tmp[t].use = static_cast