diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index bfcd4c5db..433b73981 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -300,6 +300,7 @@ Seth Pellegrino Shashvat Prabhu Shogo Yamazaki Shou-Li Hsu +Shriyans Sahoo spomatasmd Srinivasan Venkataramanan Stefan Wallentowitz diff --git a/src/V3DfgBreakCycles.cpp b/src/V3DfgBreakCycles.cpp index 22076b423..cb6d5888d 100644 --- a/src/V3DfgBreakCycles.cpp +++ b/src/V3DfgBreakCycles.cpp @@ -199,6 +199,8 @@ class TraceDriver final : public DfgVisitor { DfgVertex* m_splicep = nullptr; // The splice vertex being traced, just for assertions // Result cache for reusing already traced vertices std::unordered_map m_cache; + // Cache for boundary vertices (where m_sccInfo.get(*vtxp) != m_component) + std::unordered_map m_boundaryCache; #ifdef VL_DEBUG std::ofstream m_lineCoverageFile; // Line coverage file, just for testing @@ -269,8 +271,40 @@ class TraceDriver final : public DfgVisitor { UASSERT_OBJ(vtxp->size() > msb, vtxp, "Traced Vertex too narrow"); UASSERT_OBJ(!m_defaultp || vtxp == m_splicep, vtxp, "Tracing wrong vertex"); - // Get the cache entry, which is the resulting driver that is not part of - // the same component as vtxp + // If the currently traced vertex is in a different component, + // then we found what we were looking for. But if it's a splice + // with a corresponding default, we need to keep going as the + // splice does not fully define the value we are seeking. + if (m_sccInfo.get(*vtxp) != m_component && !m_defaultp) { + DfgVertex*& respr + = m_boundaryCache + .emplace(std::piecewise_construct, std::forward_as_tuple(vtxp, msb, lsb), + std::forward_as_tuple(nullptr)) + .first->second; + if (!respr) { + respr = 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 = respr->cast()) { + DfgVertexVar* const tmpp = createTmp("TraceDriver", splicep); + // Note: we can't do 'splicep->replaceWith(tmpp)', as other + // variable sinks of the splice might have a defaultp driver. + tmpp->srcp(splicep); + respr = tmpp; + } + // Apply a Sel to extract the relevant bits if only a part is needed + if (msb != respr->width() - 1 || lsb != 0) { + DfgSel* const selp = make(respr, msb - lsb + 1); + selp->fromp(respr); + selp->lsb(lsb); + respr = selp; + } + } + resp = respr; + break; + } + + // Normal cache for intra-component traces DfgVertex*& respr = m_cache .emplace(std::piecewise_construct, // std::forward_as_tuple(vtxp, msb, lsb), // @@ -282,28 +316,6 @@ class TraceDriver final : public DfgVisitor { // If already traced this vtxp/msb/lsb, just use the result. // This is important to avoid combinatorial explosion when the // same sub-expression is needed multiple times. - } else if (m_sccInfo.get(*vtxp) != m_component && !m_defaultp) { - // If the currently traced vertex is in a different component, - // then we found what we were looking for. But if it's a splice - // with a corresponding default, we need to keep going as the - // splice does not fully define the value we are seeking. - respr = 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 = respr->cast()) { - DfgVertexVar* const tmpp = createTmp("TraceDriver", splicep); - // Note: we can't do 'splicep->replaceWith(tmpp)', as other - // variable sinks of the splice might have a defaultp driver. - tmpp->srcp(splicep); - respr = tmpp; - } - // Apply a Sel to extract the relevant bits if only a part is needed - if (msb != respr->width() - 1 || lsb != 0) { - DfgSel* const selp = make(respr, msb - lsb + 1); - selp->fromp(respr); - selp->lsb(lsb); - respr = selp; - } } else { // Otherwise visit the vertex to trace it VL_RESTORER(m_msb);