Exclude SystemC variables from DFG

SystemC variables are fairly special (they can only be assigned to/from,
but not otherwise participate in expressions), which complicates some
DFG code. These variables only ever appear as port on the top level
wrapper, so excluding them from DFG does not make us loose any
optimizations, but simplifies internals.
This commit is contained in:
Geza Lore 2025-07-21 14:40:15 +01:00
parent a8dca71ed0
commit c2f82b1418
6 changed files with 9 additions and 28 deletions

View File

@ -639,9 +639,6 @@ DfgVertexVar* DfgVertex::getResultVar() {
this->forEachSink([&resp](DfgVertex& sink) {
DfgVertexVar* const varp = sink.cast<DfgVertexVar>();
if (!varp) return;
// Ignore SystemC variables, they cannot participate in expressions or
// be assigned rvalue expressions.
if (varp->varp()->isSc()) return;
// First variable found
if (!resp) {
resp = varp;

View File

@ -918,12 +918,14 @@ DfgVertexVar::DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVar* varp)
, m_varp{varp}
, m_varScopep{nullptr} {
UASSERT_OBJ(dfg.modulep(), varp, "Un-scoped DfgVertexVar created in scoped DfgGraph");
UASSERT_OBJ(!m_varp->isSc(), varp, "SystemC variable is not representable by DfgVertexVar");
}
DfgVertexVar::DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVarScope* vscp)
: DfgVertexUnary{dfg, type, vscp->fileline(), dtypeFor(vscp)}
, m_varp{vscp->varp()}
, m_varScopep{vscp} {
UASSERT_OBJ(!dfg.modulep(), vscp, "Scoped DfgVertexVar created in un-scoped DfgGraph");
UASSERT_OBJ(!m_varp->isSc(), vscp, "SystemC variable is not representable by DfgVertexVar");
}
//------------------------------------------------------------------------------

View File

@ -125,8 +125,9 @@ class AstToDfgVisitor final : public VNVisitor {
void markReferenced(AstNode* nodep) {
nodep->foreach([this](const AstVarRef* refp) {
// No need to (and in fact cannot) mark variables with unsupported dtypes
if (!DfgVertex::isSupportedDType(refp->varp()->dtypep())) return;
// No need to (and in fact cannot) mark variables if:
if (!DfgVertex::isSupportedDType(refp->varp()->dtypep())) return; // unsupported type
if (refp->varp()->isSc()) return; // SystemC
VariableType* const tgtp = getTarget(refp);
// Mark vertex as having a module reference outside current DFG
getNet(tgtp)->setHasModRefs();
@ -809,6 +810,7 @@ class AstToDfgVisitor final : public VNVisitor {
|| nodep->varp()->isIfaceRef() // Cannot handle interface references
|| nodep->varp()->delayp() // Cannot handle delayed variables
|| nodep->classOrPackagep() // Cannot represent cross module references
|| nodep->varp()->isSc() // SystemC variables are special and rare, we can ignore
) {
markReferenced(nodep);
m_foundUnhandled = true;

View File

@ -169,18 +169,8 @@ void V3DfgPasses::cse(DfgGraph& dfg, V3DfgCseContext& ctx) {
void V3DfgPasses::inlineVars(DfgGraph& dfg) {
for (DfgVertexVar& vtx : dfg.varVertices()) {
if (DfgVarPacked* const varp = vtx.cast<DfgVarPacked>()) {
// Don't inline SystemC variables, as SystemC types are not interchangeable with
// internal types, and hence the variables are not interchangeable either.
if (varp->hasSinks() && varp->isDrivenFullyByDfg() && !varp->varp()->isSc()) {
if (varp->hasSinks() && varp->isDrivenFullyByDfg()) {
DfgVertex* const driverp = varp->srcp();
// We must keep the original driver in certain cases, when swapping them would
// not be functionally or technically (implementation reasons) equivalent:
// 1. If driven from a SystemC variable (assignment is non-trivial)
if (DfgVertexVar* const driverVarp = driverp->cast<DfgVarPacked>()) {
if (driverVarp->varp()->isSc()) continue;
}
varp->forEachSinkEdge([=](DfgEdge& edge) { edge.relinkSource(driverp); });
}
}
@ -559,9 +549,7 @@ void V3DfgPasses::eliminateVars(DfgGraph& dfg, V3DfgEliminateVarsContext& ctx) {
varp->replaceWith(varp->srcp());
varp->nodep()->unlinkFrBack()->deleteTree();
} else if (DfgVarPacked* const driverp = varp->srcp()->cast<DfgVarPacked>()) {
// If it's driven from another variable, it can be replaced by that. However, we do not
// want to propagate SystemC variables into the design.
if (driverp->varp()->isSc()) continue;
// If it's driven from another variable, it can be replaced by that.
// Mark it for replacement
++ctx.m_varsReplaced;
UASSERT_OBJ(!varp->hasSinks(), varp, "Variable inlining should make this impossible");

View File

@ -1202,7 +1202,7 @@ class V3DfgPeephole final : public DfgVisitor {
void visit(DfgArraySel* vtxp) override {
if (DfgConst* const idxp = vtxp->bitp()->cast<DfgConst>()) {
if (DfgVarArray* const varp = vtxp->fromp()->cast<DfgVarArray>()) {
if (varp->srcp() && !varp->varp()->isForced() && !varp->varp()->isSc()) {
if (varp->srcp() && !varp->varp()->isForced()) {
if (DfgSpliceArray* const splicep = varp->srcp()->cast<DfgSpliceArray>()) {
if (DfgVertex* const driverp = splicep->driverAt(idxp->toSizeT())) {
if (!driverp->is<DfgVertexSplice>()) {

View File

@ -54,14 +54,6 @@ class DfgRegularize final {
});
return hasNonVarSink;
}
// Anything that drives an SC variable needs an intermediate,
// as we can only assign simple variables to SC variables at runtime.
const bool hasScSink = vtx.findSink<DfgVertexVar>([](const DfgVertexVar& var) { //
return var.varp()->isSc();
});
if (hasScSink) return true;
// // Splice vertices always need a variable as they represent partial updates
// if (vtx.is<DfgVertexSplice>()) return true;
// Operations without multiple sinks need no variables
if (!vtx.hasMultipleSinks()) return false;
// Array selects need no variables, they are just memory references