From 7646e7d89c072e997e9760b701cb0b476249e542 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Mon, 21 Jul 2025 18:32:08 +0100 Subject: [PATCH] Exclude SystemC variables from DFG (#6208) 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. --- src/V3Dfg.cpp | 3 --- src/V3Dfg.h | 2 ++ src/V3DfgAstToDfg.cpp | 6 ++++-- src/V3DfgPasses.cpp | 16 ++-------------- src/V3DfgPeephole.cpp | 2 +- src/V3DfgRegularize.cpp | 8 -------- 6 files changed, 9 insertions(+), 28 deletions(-) diff --git a/src/V3Dfg.cpp b/src/V3Dfg.cpp index 04679edd8..9d498a02b 100644 --- a/src/V3Dfg.cpp +++ b/src/V3Dfg.cpp @@ -639,9 +639,6 @@ DfgVertexVar* DfgVertex::getResultVar() { this->forEachSink([&resp](DfgVertex& sink) { DfgVertexVar* const varp = sink.cast(); 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; diff --git a/src/V3Dfg.h b/src/V3Dfg.h index be198cf47..a725e1a60 100644 --- a/src/V3Dfg.h +++ b/src/V3Dfg.h @@ -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"); } //------------------------------------------------------------------------------ diff --git a/src/V3DfgAstToDfg.cpp b/src/V3DfgAstToDfg.cpp index 8691b1a53..f5f4f03ed 100644 --- a/src/V3DfgAstToDfg.cpp +++ b/src/V3DfgAstToDfg.cpp @@ -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; diff --git a/src/V3DfgPasses.cpp b/src/V3DfgPasses.cpp index 717012a10..0168ba629 100644 --- a/src/V3DfgPasses.cpp +++ b/src/V3DfgPasses.cpp @@ -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()) { - // 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()) { - 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()) { - // 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"); diff --git a/src/V3DfgPeephole.cpp b/src/V3DfgPeephole.cpp index b91e34071..f308a0c7c 100644 --- a/src/V3DfgPeephole.cpp +++ b/src/V3DfgPeephole.cpp @@ -1202,7 +1202,7 @@ class V3DfgPeephole final : public DfgVisitor { void visit(DfgArraySel* vtxp) override { if (DfgConst* const idxp = vtxp->bitp()->cast()) { if (DfgVarArray* const varp = vtxp->fromp()->cast()) { - if (varp->srcp() && !varp->varp()->isForced() && !varp->varp()->isSc()) { + if (varp->srcp() && !varp->varp()->isForced()) { if (DfgSpliceArray* const splicep = varp->srcp()->cast()) { if (DfgVertex* const driverp = splicep->driverAt(idxp->toSizeT())) { if (!driverp->is()) { diff --git a/src/V3DfgRegularize.cpp b/src/V3DfgRegularize.cpp index d8de75898..64eef883a 100644 --- a/src/V3DfgRegularize.cpp +++ b/src/V3DfgRegularize.cpp @@ -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([](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()) return true; // Operations without multiple sinks need no variables if (!vtx.hasMultipleSinks()) return false; // Array selects need no variables, they are just memory references