From 63993436c9503a2ab904830b34d1ceea9e7aa8b6 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Thu, 4 Sep 2025 15:02:33 +0100 Subject: [PATCH] Fix driver tracing of partially assigned variable (#6364) (#6378) Fixes #6364 --- src/V3DfgBreakCycles.cpp | 50 ++++++++++++++++++++--------- test_regress/t/t_dfg_break_cycles.v | 22 +++++++++++++ 2 files changed, 57 insertions(+), 15 deletions(-) diff --git a/src/V3DfgBreakCycles.cpp b/src/V3DfgBreakCycles.cpp index 4a0ff6526..c043ebdc0 100644 --- a/src/V3DfgBreakCycles.cpp +++ b/src/V3DfgBreakCycles.cpp @@ -131,12 +131,27 @@ class TraceDriver final : public DfgVisitor { } } + // Create temporary capable of holding the result of 'vtxp' + DfgVertexVar* createTmp(const char* prefix, DfgVertex* vtxp) { + AstNode* nodep = m_dfg.modulep(); + if (!nodep) nodep = v3Global.rootp(); + const std::string name = m_dfg.makeUniqueName(prefix, nodep->user2Inc()); + FileLine* const flp = vtxp->fileline(); + AstNodeDType* const dtypep = vtxp->dtypep(); + DfgVertex::ScopeCache scopeCache; + AstScope* const scopep = m_dfg.modulep() ? nullptr : vtxp->scopep(scopeCache); + DfgVertexVar* const varp = m_dfg.makeNewVar(flp, name, dtypep, scopep); + varp->varp()->isInternal(true); + varp->tmpForp(varp->nodep()); + return varp; + } + // Continue tracing drivers of the given vertex, at the given LSB. Every // visitor should call this to continue the traversal, then immediately // return after the call. 'visit' methods should not call 'iterate', call // this method instead, which checks for cycles. DfgVertex* trace(DfgVertex* const vtxp, const uint32_t msb, const uint32_t lsb) { - UASSERT_OBJ(!vtxp->is(), vtxp, "Cannot trace array variables"); + UASSERT_OBJ(!vtxp->isArray(), vtxp, "Cannot trace array type vertices"); UASSERT_OBJ(vtxp->width() > msb, vtxp, "Traced Vertex too narrow"); // Push to stack @@ -163,22 +178,24 @@ class TraceDriver final : public DfgVisitor { // Trace the vertex onStackr = true; - // If the currently traced vertex is in a different component, then we - // found what we were looking for. However, keep going past a splice, - // or a unit as they cannot be use directly (they must always feed into - // a variable, so we can't make them drive arbitrary logic) - if (m_vtx2Scc[vtxp] != m_component // - && !vtxp->is() // - && !vtxp->is()) { - if (msb != vtxp->width() - 1 || lsb != 0) { - // Apply a Sel to extract the relevant bits if only a part is needed - DfgSel* const selp = make(vtxp, msb - lsb + 1); - selp->fromp(vtxp); + // If the currently traced vertex is in a different component, + // then we found what we were looking for. + if (m_vtx2Scc[vtxp] != m_component) { + m_resp = vtxp; + // If the result is a splice, we need to insert a temporary for it + // as a splice cannot be fed into arbitray logic + if (DfgVertexSplice* const splicep = m_resp->cast()) { + DfgVertexVar* const tmpp = createTmp("TraceDriver", splicep); + splicep->replaceWith(tmpp); + tmpp->srcp(splicep); + m_resp = tmpp; + } + // Apply a Sel to extract the relevant bits if only a part is needed + if (msb != m_resp->width() - 1 || lsb != 0) { + DfgSel* const selp = make(m_resp, msb - lsb + 1); + selp->fromp(m_resp); selp->lsb(lsb); m_resp = selp; - } else { - // Otherwise just return the vertex - m_resp = vtxp; } } else { // Otherwise visit the vertex @@ -1290,6 +1307,9 @@ V3DfgPasses::breakCycles(const DfgGraph& dfg, V3DfgContext& ctx) { return {nullptr, false}; } + // AstNetlist/AstNodeModule user2 used as sequence numbers for temporaries + const VNUser2InUse user2InUse; + // Show input for debugging dump(7, dfg, "input"); diff --git a/test_regress/t/t_dfg_break_cycles.v b/test_regress/t/t_dfg_break_cycles.v index ad794c052..4413dff92 100644 --- a/test_regress/t/t_dfg_break_cycles.v +++ b/test_regress/t/t_dfg_break_cycles.v @@ -227,4 +227,26 @@ module t ( `signal(ALWAYS_2, 4); // UNOPTFLAT assign ALWAYS_2 = always_2; // verilator lint_on ALWCOMBORDER + + logic [31:0] array_4[3]; // UNOPTFLAT + // Input + assign array_4[0] = rand_a[31:0]; + // Sums 1 + assign array_4[1][ 0 +: 3] = array_4[0][ 2 +: 2] + array_4[0][ 0 +: 2]; + assign array_4[1][ 3 +: 3] = array_4[0][ 6 +: 2] + array_4[0][ 4 +: 2]; + assign array_4[1][ 6 +: 3] = array_4[0][10 +: 2] + array_4[0][ 8 +: 2]; + assign array_4[1][ 9 +: 3] = array_4[0][14 +: 2] + array_4[0][12 +: 2]; + assign array_4[1][12 +: 3] = array_4[0][18 +: 2] + array_4[0][16 +: 2]; + assign array_4[1][15 +: 3] = array_4[0][22 +: 2] + array_4[0][20 +: 2]; + assign array_4[1][18 +: 3] = array_4[0][26 +: 2] + array_4[0][24 +: 2]; + assign array_4[1][21 +: 3] = array_4[0][30 +: 2] + array_4[0][28 +: 2]; + // Sums 2 + assign array_4[2][ 0 +: 4] = array_4[1][ 3 +: 3] + array_4[1][ 0 +: 3]; + assign array_4[2][ 4 +: 4] = array_4[1][ 9 +: 3] + array_4[1][ 6 +: 3]; + assign array_4[2][ 8 +: 4] = array_4[1][15 +: 3] + array_4[1][12 +: 3]; + assign array_4[2][12 +: 4] = array_4[1][21 +: 3] + array_4[1][18 +: 3]; + // Outupt + `signal(ARRAY_4, 32); + assign ARRAY_4 = array_4[2]; + endmodule