Internals: Do not optimize variables with RW refs in Dfg

This commit is contained in:
Geza Lore 2026-03-26 10:04:31 +00:00
parent f12cdac8da
commit 9ed7a9f98b
4 changed files with 60 additions and 38 deletions

View File

@ -68,37 +68,6 @@ class DfgVisitor;
template <typename T_User, bool = fitsSpaceAllocatedFor<T_User, void*>()>
class DfgUserMap;
namespace V3Dfg {
//-----------------------------------------------------------------------
// Functions for compatibility tests
// Returns true if variable can be represented in the graph
inline bool isSupported(const AstVar* varp) {
if (varp->isIfaceRef()) return false; // Cannot handle interface references
if (varp->delayp()) return false; // Cannot handle delayed variables
if (varp->isSc()) return false; // SystemC variables are special and rare, we can ignore
if (varp->dfgMultidriven()) return false; // Discovered as multidriven on earlier DFG run
return DfgDataType::fromAst(varp->dtypep());
}
// Returns true if variable can be represented in the graph
inline bool isSupported(const AstVarScope* vscp) {
const AstNodeModule* const modp = vscp->scopep()->modp();
if (VN_IS(modp, Module)) {
// Regular module supported
} else if (const AstIface* const ifacep = VN_CAST(modp, Iface)) {
// Interfaces supported if there are no virtual interfaces for
// them, otherwise they cannot be resovled statically.
if (ifacep->hasVirtualRef()) return false;
} else {
return false; // Anything else (package, class, etc) not supported
}
// Check the AstVar
return isSupported(vscp->varp());
}
} //namespace V3Dfg
//------------------------------------------------------------------------------
// Dataflow graph vertex type enum
@ -574,6 +543,39 @@ public:
sinkCone(const std::vector<const DfgVertex*>&) const VL_MT_DISABLED;
};
namespace V3Dfg {
//-----------------------------------------------------------------------
// Functions for compatibility tests
// Returns true if variable can be represented in the graph
inline bool isSupported(const AstVar* varp) {
if (varp->isIfaceRef()) return false; // Cannot handle interface references
if (varp->delayp()) return false; // Cannot handle delayed variables
if (varp->isSc()) return false; // SystemC variables are special and rare, we can ignore
if (varp->dfgMultidriven()) return false; // Discovered as multidriven on earlier DFG run
if (DfgVertexVar::hasRWRefs(varp)) return false; // Referenced via READWRITE references
return DfgDataType::fromAst(varp->dtypep());
}
// Returns true if variable can be represented in the graph
inline bool isSupported(const AstVarScope* vscp) {
const AstNodeModule* const modp = vscp->scopep()->modp();
if (VN_IS(modp, Module)) {
// Regular module supported
} else if (const AstIface* const ifacep = VN_CAST(modp, Iface)) {
// Interfaces supported if there are no virtual interfaces for
// them, otherwise they cannot be resovled statically.
if (ifacep->hasVirtualRef()) return false;
} else {
return false; // Anything else (package, class, etc) not supported
}
if (DfgVertexVar::hasRWRefs(vscp)) return false; // Referenced via READWRITE references
// Check the AstVar
return isSupported(vscp->varp());
}
} //namespace V3Dfg
//------------------------------------------------------------------------------
// Map from DfgVertices to T_Value implemeneted via DfgVertex::m_userStorage

View File

@ -246,7 +246,8 @@ class DataflowOptimize final {
// - bit1: Written via AstVarXRef (hierarchical reference)
// - bit2: Read by logic in same module/netlist not represented in DFG
// - bit3: Written by logic in same module/netlist not represented in DFG
// - bit31-4: Reference count, how many DfgVertexVar represent this variable
// - bit4: Has READWRITE references
// - bit31-5: Reference count, how many DfgVertexVar represent this variable
//
// AstNode::user2/user3/user4 can be used by various DFG algorithms
const VNUser1InUse m_user1InUse;
@ -285,6 +286,12 @@ class DataflowOptimize final {
senItemp->foreach([](const AstVarRef* refp) {
DfgVertexVar::setHasExtRdRefs(refp->varScopep());
});
return;
}
// Check direct references
if (const AstVarRef* const refp = VN_CAST(nodep, VarRef)) {
if (refp->access().isRW()) DfgVertexVar::setHasRWRefs(refp->varScopep());
return;
}
} else {
if (AstVar* const varp = VN_CAST(nodep, Var)) {
@ -296,13 +303,20 @@ class DataflowOptimize final {
if (hasExtWr) DfgVertexVar::setHasExtWrRefs(varp);
return;
}
// Check direct references
if (const AstVarRef* const refp = VN_CAST(nodep, VarRef)) {
if (refp->access().isRW()) DfgVertexVar::setHasRWRefs(refp->varp());
return;
}
}
// Check hierarchical references
if (const AstVarXRef* const xrefp = VN_CAST(nodep, VarXRef)) {
AstVar* const tgtp = xrefp->varp();
if (!tgtp) return;
if (xrefp->access().isReadOrRW()) DfgVertexVar::setHasExtRdRefs(tgtp);
if (xrefp->access().isWriteOrRW()) DfgVertexVar::setHasExtWrRefs(tgtp);
if (xrefp->access().isRW()) DfgVertexVar::setHasRWRefs(tgtp);
return;
}
// Check cell ports

View File

@ -145,6 +145,7 @@ class AstToDfgConverter final : public VNVisitor {
// Returns {nullptr, 0}, if the given LValue expression is not supported.
std::pair<DfgVertexSplice*, uint32_t> convertLValue(AstNodeExpr* nodep) {
if (const AstVarRef* const vrefp = VN_CAST(nodep, VarRef)) {
UASSERT_OBJ(vrefp->access().isWriteOnly(), vrefp, "Non-WriteOnly reference");
if (!isSupported(vrefp)) {
++m_ctx.m_conv.nonRepLValue;
return {nullptr, 0};
@ -366,7 +367,8 @@ class AstToDfgConverter final : public VNVisitor {
UASSERT_OBJ(!nodep->user2p(), nodep, "Already has Dfg vertex");
if (unhandled(nodep)) return;
// This visit method is only called on RValues, where only read refs are supported
if (!nodep->access().isReadOnly() || !isSupported(nodep)) {
UASSERT_OBJ(nodep->access().isReadOnly(), nodep, "Non-ReadOnly reference");
if (!isSupported(nodep)) {
m_foundUnhandled = true;
++m_ctx.m_conv.nonRepVarRef;
return;

View File

@ -70,8 +70,8 @@ class DfgVertexVar VL_NOT_FINAL : public DfgVertex {
#endif
// Increment reference count
AstNode* const variablep = nodep();
variablep->user1(variablep->user1() + 0x10);
UASSERT_OBJ((variablep->user1() >> 4) > 0, variablep, "Reference count overflow");
variablep->user1(variablep->user1() + 0x20);
UASSERT_OBJ((variablep->user1() >> 5) > 0, variablep, "Reference count overflow");
// Allocate sources
newInput();
newInput();
@ -87,8 +87,8 @@ public:
~DfgVertexVar() {
// Decrement reference count
AstNode* const variablep = nodep();
variablep->user1(variablep->user1() - 0x10);
UASSERT_OBJ((variablep->user1() >> 4) >= 0, variablep, "Reference count underflow");
variablep->user1(variablep->user1() - 0x20);
UASSERT_OBJ((variablep->user1() >> 5) >= 0, variablep, "Reference count underflow");
}
ASTGEN_MEMBERS_DfgVertexVar;
@ -118,7 +118,7 @@ public:
void driverFileLine(FileLine* flp) { m_driverFileLine = flp; }
// Variable referenced from other DFG in the same module/netlist
bool hasDfgRefs() const { return nodep()->user1() >> 5; } // I.e.: (nodep()->user1() >> 4) > 1
bool hasDfgRefs() const { return nodep()->user1() >> 6; } // I.e.: (nodep()->user1() >> 5) > 1
// Variable referenced from Ast code in the same module/netlist
static bool hasModRdRefs(const AstNode* nodep) { return nodep->user1() & 0x04; }
@ -140,6 +140,10 @@ public:
bool hasExtWrRefs() const { return hasExtWrRefs(nodep()); }
bool hasExtRefs() const { return hasExtRdRefs() || hasExtWrRefs(); }
// Variable referenced via READWRITE references
static bool hasRWRefs(const AstNode* nodep) { return nodep->user1() & 0x10; }
static void setHasRWRefs(AstNode* nodep) { nodep->user1(nodep->user1() | 0x10); }
// True iff the value of this variable is read outside this DfgGraph
bool isObserved() const {
// A DfgVarVertex is written in exactly one DfgGraph, and might be read in an arbitrary